Imported Upstream version 5.11 upstream/5.11
authorWu Zheng <wu.zheng@intel.com>
Wed, 27 Nov 2013 02:36:00 +0000 (21:36 -0500)
committerWu Zheng <wu.zheng@intel.com>
Wed, 27 Nov 2013 02:36:00 +0000 (21:36 -0500)
98 files changed:
ChangeLog
Makefile.am
Makefile.android [deleted file]
Makefile.in
Makefile.tools
android/Android.mk
android/Makefile.am [new file with mode: 0644]
android/README [new file with mode: 0644]
android/a2dp.c [new file with mode: 0644]
android/a2dp.h [new file with mode: 0644]
android/bluetooth.c [new file with mode: 0644]
android/bluetooth.h [new file with mode: 0644]
android/client/haltest.c [new file with mode: 0644]
android/client/history.c [new file with mode: 0644]
android/client/history.h [new file with mode: 0644]
android/client/hwmodule.c [new file with mode: 0644]
android/client/if-av.c [new file with mode: 0644]
android/client/if-bt.c [new file with mode: 0644]
android/client/if-gatt.c [new file with mode: 0644]
android/client/if-hf.c [new file with mode: 0644]
android/client/if-hh.c [new file with mode: 0644]
android/client/if-main.h [new file with mode: 0644]
android/client/if-pan.c [new file with mode: 0644]
android/client/if-sock.c [new file with mode: 0644]
android/client/pollhandler.c [new file with mode: 0644]
android/client/pollhandler.h [new file with mode: 0644]
android/client/tabcompletion.c [new file with mode: 0644]
android/client/terminal.c [new file with mode: 0644]
android/client/terminal.h [new file with mode: 0644]
android/cutils/properties.h [new file with mode: 0644]
android/hal-a2dp.c [new file with mode: 0644]
android/hal-bluetooth.c [new file with mode: 0644]
android/hal-hidhost.c [new file with mode: 0644]
android/hal-ipc-api.txt
android/hal-ipc.c [new file with mode: 0644]
android/hal-ipc.h [new file with mode: 0644]
android/hal-log.h [new file with mode: 0644]
android/hal-msg.h [new file with mode: 0644]
android/hal-pan.c [new file with mode: 0644]
android/hal-sock.c [new file with mode: 0644]
android/hal-utils.c [new file with mode: 0644]
android/hal-utils.h [new file with mode: 0644]
android/hal.h [new file with mode: 0644]
android/hardware/bluetooth.h [new file with mode: 0644]
android/hardware/bt_av.h [new file with mode: 0644]
android/hardware/bt_gatt.h [new file with mode: 0644]
android/hardware/bt_gatt_client.h [new file with mode: 0644]
android/hardware/bt_gatt_server.h [new file with mode: 0644]
android/hardware/bt_gatt_types.h [new file with mode: 0644]
android/hardware/bt_hf.h [new file with mode: 0644]
android/hardware/bt_hh.h [new file with mode: 0644]
android/hardware/bt_hl.h [new file with mode: 0644]
android/hardware/bt_pan.h [new file with mode: 0644]
android/hardware/bt_rc.h [new file with mode: 0644]
android/hardware/bt_sock.h [new file with mode: 0644]
android/hardware/hardware.h [new file with mode: 0644]
android/hidhost.c [new file with mode: 0644]
android/hidhost.h [new file with mode: 0644]
android/ipc.c [new file with mode: 0644]
android/ipc.h [new file with mode: 0644]
android/main.c
android/pan.c [new file with mode: 0644]
android/pan.h [new file with mode: 0644]
android/socket.c [new file with mode: 0644]
android/socket.h [new file with mode: 0644]
android/system-emulator.c [new file with mode: 0644]
android/utils.h [moved from android/log.c with 53% similarity]
configure
configure.ac
doc/obex-api.txt
emulator/bthost.c
emulator/bthost.h
gdbus/object.c
lib/bluetooth.c
monitor/bt.h
monitor/display.c
monitor/display.h
monitor/main.c
monitor/packet.c
monitor/packet.h
obexd/src/main.c
plugins/wiimote.c
profiles/audio/a2dp.c
profiles/audio/avdtp.c
profiles/audio/avdtp.h
profiles/audio/avrcp.c
src/adapter.c
src/adapter.h
src/bluetooth.service.in
src/device.c
src/sdp-client.c
src/service.c
src/shared/mgmt.h
tools/hid2hci.c
tools/l2cap-tester.c
tools/l2test.c
tools/mgmt-tester.c
tools/smp-tester.c [new file with mode: 0644]

index fc9b3d7..ca48336 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+ver 5.11:
+       Fix issue with connection attempt when not powered.
+       Fix issue with assigning player to AVRCP target role.
+       Fix issue with OBEX default cache directory.
+       Fix issue with SDP search error handling.
+       Fix issue with processing of SDP records.
+       Fix issue with HID to HCI switching utility.
+       Fix issue with mgmt end-to-end testing tool.
+       Fix issue with L2CAP end-to-end testing tool.
+       Add support for SMP end-to-end testing tool.
+       Add support for more Wii controllers.
+
 ver 5.10:
        Fix issue with discoverable timeout handling.
        Fix issue with MAP messages and record version.
index 8aed6f7..328ccdb 100644 (file)
@@ -80,7 +80,7 @@ include_HEADERS += $(lib_headers)
 lib_LTLIBRARIES += lib/libbluetooth.la
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:2:17
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 endif
 
@@ -179,7 +179,7 @@ test_scripts =
 
 include Makefile.tools
 include Makefile.obexd
-include Makefile.android
+include android/Makefile.am
 
 if HID2HCI
 rulesdir = @UDEV_DIR@/rules.d
diff --git a/Makefile.android b/Makefile.android
deleted file mode 100644 (file)
index 3ceefd8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-if ANDROID
-noinst_PROGRAMS += android/bluetoothd
-
-android_bluetoothd_SOURCES = android/main.c src/log.c
-android_bluetoothd_LDADD = @GLIB_LIBS@
-endif
-
-EXTRA_DIST += android/Android.mk android/log.c
-
-EXTRA_DIST += android/hal-ipc-api.txt
index 677ad3e..9556969 100644 (file)
@@ -63,11 +63,11 @@ libexec_PROGRAMS = src/bluetoothd$(EXEEXT) obexd/src/obexd$(EXEEXT)
 @LIBRARY_TRUE@am__append_1 = $(lib_headers)
 @LIBRARY_TRUE@am__append_2 = lib/libbluetooth.la
 DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \
-       $(dist_man_MANS) $(srcdir)/Makefile.am \
-       $(srcdir)/Makefile.android $(srcdir)/Makefile.in \
+       $(dist_man_MANS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
        $(srcdir)/Makefile.obexd $(srcdir)/Makefile.plugins \
-       $(srcdir)/Makefile.tools $(srcdir)/config.h.in \
-       $(top_srcdir)/configure $(top_srcdir)/lib/bluez.pc.in \
+       $(srcdir)/Makefile.tools $(srcdir)/android/Makefile.am \
+       $(srcdir)/config.h.in $(top_srcdir)/configure \
+       $(top_srcdir)/lib/bluez.pc.in \
        $(top_srcdir)/src/bluetoothd.8.in AUTHORS COPYING COPYING.LIB \
        ChangeLog INSTALL NEWS TODO compile config.guess config.sub \
        depcomp install-sh ltmain.sh missing
@@ -114,11 +114,12 @@ DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \
 @EXPERIMENTAL_TRUE@am__append_15 = emulator/btvirt emulator/b1ee \
 @EXPERIMENTAL_TRUE@    tools/mgmt-tester tools/gap-tester \
 @EXPERIMENTAL_TRUE@    tools/l2cap-tester tools/sco-tester \
-@EXPERIMENTAL_TRUE@    tools/bdaddr tools/avinfo tools/avtest \
-@EXPERIMENTAL_TRUE@    tools/scotest tools/amptest tools/hwdb \
-@EXPERIMENTAL_TRUE@    tools/hcieventmask tools/hcisecfilter \
-@EXPERIMENTAL_TRUE@    tools/btmgmt tools/btinfo tools/btattach \
-@EXPERIMENTAL_TRUE@    tools/btsnoop tools/btiotest tools/cltest \
+@EXPERIMENTAL_TRUE@    tools/smp-tester tools/bdaddr tools/avinfo \
+@EXPERIMENTAL_TRUE@    tools/avtest tools/scotest tools/amptest \
+@EXPERIMENTAL_TRUE@    tools/hwdb tools/hcieventmask \
+@EXPERIMENTAL_TRUE@    tools/hcisecfilter tools/btmgmt \
+@EXPERIMENTAL_TRUE@    tools/btinfo tools/btattach tools/btsnoop \
+@EXPERIMENTAL_TRUE@    tools/btiotest tools/cltest \
 @EXPERIMENTAL_TRUE@    tools/mpris-player
 @TOOLS_TRUE@am__append_16 = tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
 @TOOLS_TRUE@                   tools/rfcomm tools/rctest tools/l2test tools/l2ping \
@@ -151,8 +152,10 @@ DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \
 @OBEX_TRUE@    obexd/plugins/vcard.h obexd/plugins/vcard.c \
 @OBEX_TRUE@    obexd/plugins/phonebook.h \
 @OBEX_TRUE@    obexd/plugins/phonebook-dummy.c
-@ANDROID_TRUE@am__append_28 = android/bluetoothd
-@HID2HCI_TRUE@am__append_29 = $(rules_DATA)
+@ANDROID_TRUE@am__append_28 = android/system-emulator \
+@ANDROID_TRUE@ android/bluetoothd android/haltest
+@ANDROID_TRUE@am__append_29 = android/libhal-internal.la
+@HID2HCI_TRUE@am__append_30 = $(rules_DATA)
 TESTS = $(am__EXEEXT_8)
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -221,14 +224,36 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \
        "$(DESTDIR)$(systemduserunitdir)" "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \
        $(plugin_LTLIBRARIES)
+android_libhal_internal_la_LIBADD =
+am__android_libhal_internal_la_SOURCES_DIST = android/hal.h \
+       android/hal-bluetooth.c android/hal-sock.c \
+       android/hal-hidhost.c android/hal-pan.c android/hal-a2dp.c \
+       android/hardware/bluetooth.h android/hardware/bt_av.h \
+       android/hardware/bt_gatt.h android/hardware/bt_gatt_client.h \
+       android/hardware/bt_gatt_server.h \
+       android/hardware/bt_gatt_types.h android/hardware/bt_hf.h \
+       android/hardware/bt_hh.h android/hardware/bt_hl.h \
+       android/hardware/bt_pan.h android/hardware/bt_rc.h \
+       android/hardware/bt_sock.h android/hardware/hardware.h \
+       android/cutils/properties.h android/hal-log.h \
+       android/hal-ipc.h android/hal-ipc.c
+@ANDROID_TRUE@am_android_libhal_internal_la_OBJECTS = android/android_libhal_internal_la-hal-bluetooth.lo \
+@ANDROID_TRUE@ android/android_libhal_internal_la-hal-sock.lo \
+@ANDROID_TRUE@ android/android_libhal_internal_la-hal-hidhost.lo \
+@ANDROID_TRUE@ android/android_libhal_internal_la-hal-pan.lo \
+@ANDROID_TRUE@ android/android_libhal_internal_la-hal-a2dp.lo \
+@ANDROID_TRUE@ android/android_libhal_internal_la-hal-ipc.lo
+android_libhal_internal_la_OBJECTS =  \
+       $(am_android_libhal_internal_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+@ANDROID_TRUE@am_android_libhal_internal_la_rpath =
 gdbus_libgdbus_internal_la_LIBADD =
 am_gdbus_libgdbus_internal_la_OBJECTS = gdbus/mainloop.lo \
        gdbus/watch.lo gdbus/object.lo gdbus/client.lo gdbus/polkit.lo
 gdbus_libgdbus_internal_la_OBJECTS =  \
        $(am_gdbus_libgdbus_internal_la_OBJECTS)
-AM_V_lt = $(am__v_lt_@AM_V@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
 lib_libbluetooth_internal_la_LIBADD =
 am__objects_1 =
 am__objects_2 = lib/bluetooth.lo lib/hci.lo lib/sdp.lo
@@ -275,6 +300,7 @@ plugins_external_dummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 @EXPERIMENTAL_TRUE@    tools/gap-tester$(EXEEXT) \
 @EXPERIMENTAL_TRUE@    tools/l2cap-tester$(EXEEXT) \
 @EXPERIMENTAL_TRUE@    tools/sco-tester$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/smp-tester$(EXEEXT) \
 @EXPERIMENTAL_TRUE@    tools/bdaddr$(EXEEXT) tools/avinfo$(EXEEXT) \
 @EXPERIMENTAL_TRUE@    tools/avtest$(EXEEXT) \
 @EXPERIMENTAL_TRUE@    tools/scotest$(EXEEXT) \
@@ -293,7 +319,9 @@ plugins_external_dummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 @READLINE_TRUE@        tools/bluetooth-player$(EXEEXT) \
 @READLINE_TRUE@        tools/obexctl$(EXEEXT)
 @EXPERIMENTAL_TRUE@am__EXEEXT_6 = profiles/iap/iapd$(EXEEXT)
-@ANDROID_TRUE@am__EXEEXT_7 = android/bluetoothd$(EXEEXT)
+@ANDROID_TRUE@am__EXEEXT_7 = android/system-emulator$(EXEEXT) \
+@ANDROID_TRUE@ android/bluetoothd$(EXEEXT) \
+@ANDROID_TRUE@ android/haltest$(EXEEXT)
 am__EXEEXT_8 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \
        unit/test-textfile$(EXEEXT) unit/test-crc$(EXEEXT) \
        unit/test-mgmt$(EXEEXT) unit/test-sdp$(EXEEXT) \
@@ -304,11 +332,71 @@ am__EXEEXT_8 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \
        unit/test-gobex-apparam$(EXEEXT) unit/test-lib$(EXEEXT)
 PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(libexec_PROGRAMS) \
        $(noinst_PROGRAMS) $(udev_PROGRAMS)
-am__android_bluetoothd_SOURCES_DIST = android/main.c src/log.c
+am__android_bluetoothd_SOURCES_DIST = android/main.c src/log.c \
+       android/hal-msg.h android/utils.h src/sdpd-database.c \
+       src/sdpd-server.c src/sdpd-service.c src/sdpd-request.c \
+       src/glib-helper.h src/glib-helper.c src/eir.h src/eir.c \
+       src/shared/util.h src/shared/util.c src/shared/mgmt.h \
+       src/shared/mgmt.c android/bluetooth.h android/bluetooth.c \
+       android/hidhost.h android/hidhost.c android/ipc.h \
+       android/ipc.c android/a2dp.h android/a2dp.c android/socket.h \
+       android/socket.c android/pan.h android/pan.c btio/btio.h \
+       btio/btio.c src/sdp-client.h src/sdp-client.c
 @ANDROID_TRUE@am_android_bluetoothd_OBJECTS = android/main.$(OBJEXT) \
-@ANDROID_TRUE@ src/log.$(OBJEXT)
+@ANDROID_TRUE@ src/log.$(OBJEXT) src/sdpd-database.$(OBJEXT) \
+@ANDROID_TRUE@ src/sdpd-server.$(OBJEXT) \
+@ANDROID_TRUE@ src/sdpd-service.$(OBJEXT) \
+@ANDROID_TRUE@ src/sdpd-request.$(OBJEXT) \
+@ANDROID_TRUE@ src/glib-helper.$(OBJEXT) src/eir.$(OBJEXT) \
+@ANDROID_TRUE@ src/shared/util.$(OBJEXT) \
+@ANDROID_TRUE@ src/shared/mgmt.$(OBJEXT) \
+@ANDROID_TRUE@ android/bluetooth.$(OBJEXT) \
+@ANDROID_TRUE@ android/hidhost.$(OBJEXT) android/ipc.$(OBJEXT) \
+@ANDROID_TRUE@ android/a2dp.$(OBJEXT) android/socket.$(OBJEXT) \
+@ANDROID_TRUE@ android/pan.$(OBJEXT) btio/btio.$(OBJEXT) \
+@ANDROID_TRUE@ src/sdp-client.$(OBJEXT)
 android_bluetoothd_OBJECTS = $(am_android_bluetoothd_OBJECTS)
-android_bluetoothd_DEPENDENCIES =
+@ANDROID_TRUE@android_bluetoothd_DEPENDENCIES =  \
+@ANDROID_TRUE@ lib/libbluetooth-internal.la
+am__android_haltest_SOURCES_DIST = android/client/haltest.c \
+       android/client/pollhandler.h android/client/pollhandler.c \
+       android/client/terminal.h android/client/terminal.c \
+       android/client/history.h android/client/history.c \
+       android/client/tabcompletion.c android/client/if-main.h \
+       android/client/if-av.c android/client/if-bt.c \
+       android/client/if-gatt.c android/client/if-hf.c \
+       android/client/if-hh.c android/client/if-pan.c \
+       android/client/if-sock.c android/client/hwmodule.c \
+       android/hal-utils.h android/hal-utils.c
+@ANDROID_TRUE@am_android_haltest_OBJECTS = android/client/android_haltest-haltest.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-pollhandler.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-terminal.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-history.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-tabcompletion.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-av.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-bt.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-gatt.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-hf.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-hh.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-pan.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-if-sock.$(OBJEXT) \
+@ANDROID_TRUE@ android/client/android_haltest-hwmodule.$(OBJEXT) \
+@ANDROID_TRUE@ android/android_haltest-hal-utils.$(OBJEXT)
+android_haltest_OBJECTS = $(am_android_haltest_OBJECTS)
+@ANDROID_TRUE@android_haltest_DEPENDENCIES =  \
+@ANDROID_TRUE@ android/libhal-internal.la
+android_haltest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(android_haltest_CFLAGS) $(CFLAGS) $(android_haltest_LDFLAGS) \
+       $(LDFLAGS) -o $@
+am__android_system_emulator_SOURCES_DIST = android/system-emulator.c \
+       monitor/mainloop.h monitor/mainloop.c
+@ANDROID_TRUE@am_android_system_emulator_OBJECTS =  \
+@ANDROID_TRUE@ android/system-emulator.$(OBJEXT) \
+@ANDROID_TRUE@ monitor/mainloop.$(OBJEXT)
+android_system_emulator_OBJECTS =  \
+       $(am_android_system_emulator_OBJECTS)
+android_system_emulator_LDADD = $(LDADD)
 am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \
        attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \
        attrib/interactive.c attrib/utils.c src/log.c client/display.c \
@@ -906,6 +994,22 @@ am__tools_sdptool_SOURCES_DIST = tools/sdptool.c src/sdp-xml.h \
 @TOOLS_TRUE@   src/sdp-xml.$(OBJEXT)
 tools_sdptool_OBJECTS = $(am_tools_sdptool_OBJECTS)
 @TOOLS_TRUE@tools_sdptool_DEPENDENCIES = lib/libbluetooth-internal.la
+am__tools_smp_tester_SOURCES_DIST = tools/smp-tester.c monitor/bt.h \
+       emulator/btdev.h emulator/btdev.c emulator/bthost.h \
+       emulator/bthost.c src/shared/util.h src/shared/util.c \
+       src/shared/mgmt.h src/shared/mgmt.c src/shared/hciemu.h \
+       src/shared/hciemu.c src/shared/tester.h src/shared/tester.c
+@EXPERIMENTAL_TRUE@am_tools_smp_tester_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/smp-tester.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/util.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/mgmt.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/hciemu.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/tester.$(OBJEXT)
+tools_smp_tester_OBJECTS = $(am_tools_smp_tester_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_smp_tester_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 am_unit_test_crc_OBJECTS = unit/test-crc.$(OBJEXT) \
        monitor/crc.$(OBJEXT)
 unit_test_crc_OBJECTS = $(am_unit_test_crc_OBJECTS)
@@ -983,11 +1087,13 @@ AM_V_GEN = $(am__v_GEN_@AM_V@)
 am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
 am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(profiles_sap_libsap_a_SOURCES) \
+       $(android_libhal_internal_la_SOURCES) \
        $(gdbus_libgdbus_internal_la_SOURCES) \
        $(lib_libbluetooth_internal_la_SOURCES) \
        $(lib_libbluetooth_la_SOURCES) \
        $(plugins_external_dummy_la_SOURCES) \
-       $(android_bluetoothd_SOURCES) $(attrib_gatttool_SOURCES) \
+       $(android_bluetoothd_SOURCES) $(android_haltest_SOURCES) \
+       $(android_system_emulator_SOURCES) $(attrib_gatttool_SOURCES) \
        $(client_bluetoothctl_SOURCES) $(emulator_b1ee_SOURCES) \
        $(emulator_btvirt_SOURCES) $(monitor_btmon_SOURCES) \
        $(obexd_src_obexd_SOURCES) $(nodist_obexd_src_obexd_SOURCES) \
@@ -1010,20 +1116,23 @@ SOURCES = $(profiles_sap_libsap_a_SOURCES) \
        $(tools_obex_server_tool_SOURCES) $(tools_obexctl_SOURCES) \
        tools/rctest.c tools/rfcomm.c $(tools_sco_tester_SOURCES) \
        tools/scotest.c $(tools_sdptool_SOURCES) \
-       $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \
-       $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \
-       $(unit_test_gobex_apparam_SOURCES) \
+       $(tools_smp_tester_SOURCES) $(unit_test_crc_SOURCES) \
+       $(unit_test_eir_SOURCES) $(unit_test_gdbus_client_SOURCES) \
+       $(unit_test_gobex_SOURCES) $(unit_test_gobex_apparam_SOURCES) \
        $(unit_test_gobex_header_SOURCES) \
        $(unit_test_gobex_packet_SOURCES) \
        $(unit_test_gobex_transfer_SOURCES) $(unit_test_lib_SOURCES) \
        $(unit_test_mgmt_SOURCES) $(unit_test_sdp_SOURCES) \
        $(unit_test_textfile_SOURCES) $(unit_test_uuid_SOURCES)
 DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \
+       $(am__android_libhal_internal_la_SOURCES_DIST) \
        $(gdbus_libgdbus_internal_la_SOURCES) \
        $(lib_libbluetooth_internal_la_SOURCES) \
        $(am__lib_libbluetooth_la_SOURCES_DIST) \
        $(am__plugins_external_dummy_la_SOURCES_DIST) \
        $(am__android_bluetoothd_SOURCES_DIST) \
+       $(am__android_haltest_SOURCES_DIST) \
+       $(am__android_system_emulator_SOURCES_DIST) \
        $(am__attrib_gatttool_SOURCES_DIST) \
        $(am__client_bluetoothctl_SOURCES_DIST) \
        $(am__emulator_b1ee_SOURCES_DIST) \
@@ -1055,9 +1164,9 @@ DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \
        $(am__tools_obexctl_SOURCES_DIST) tools/rctest.c \
        tools/rfcomm.c $(am__tools_sco_tester_SOURCES_DIST) \
        tools/scotest.c $(am__tools_sdptool_SOURCES_DIST) \
-       $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \
-       $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \
-       $(unit_test_gobex_apparam_SOURCES) \
+       $(am__tools_smp_tester_SOURCES_DIST) $(unit_test_crc_SOURCES) \
+       $(unit_test_eir_SOURCES) $(unit_test_gdbus_client_SOURCES) \
+       $(unit_test_gobex_SOURCES) $(unit_test_gobex_apparam_SOURCES) \
        $(unit_test_gobex_header_SOURCES) \
        $(unit_test_gobex_packet_SOURCES) \
        $(unit_test_gobex_transfer_SOURCES) $(unit_test_lib_SOURCES) \
@@ -1254,19 +1363,19 @@ AM_MAKEFLAGS = --no-print-directory
 lib_LTLIBRARIES = $(am__append_2)
 noinst_LIBRARIES = $(am__append_7)
 noinst_LTLIBRARIES = lib/libbluetooth-internal.la \
-       gdbus/libgdbus-internal.la
+       gdbus/libgdbus-internal.la $(am__append_29)
 dist_man_MANS = $(am__append_17) $(am__append_19)
 dist_noinst_MANS = 
 CLEANFILES = $(builtin_files) src/bluetooth.service \
        obexd/src/builtin.h $(builtin_files) obexd/src/obex.service \
-       $(am__append_29)
+       $(am__append_30)
 EXTRA_DIST = src/bluetooth.service.in src/org.bluez.service \
        src/genbuiltin src/bluetooth.conf src/main.conf \
        profiles/network/network.conf profiles/input/input.conf \
        profiles/proximity/proximity.conf $(am__append_18) \
        $(am__append_20) $(am__append_21) obexd/src/obex.service.in \
        obexd/src/org.bluez.obex.service obexd/src/genbuiltin \
-       android/Android.mk android/log.c android/hal-ipc-api.txt \
+       android/Android.mk android/hal-ipc-api.txt android/README \
        tools/hid2hci.rules $(test_scripts) doc/assigned-numbers.txt \
        doc/supported-features.txt doc/mgmt-api.txt \
        doc/adapter-api.txt doc/device-api.txt doc/agent-api.txt \
@@ -1303,7 +1412,7 @@ extra_sources = lib/uuid.c
 local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
 BUILT_SOURCES = $(local_headers) src/builtin.h obexd/src/builtin.h
 @LIBRARY_TRUE@lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17
+@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:2:17
 @LIBRARY_TRUE@lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \
                                        $(extra_headers) $(extra_sources)
@@ -1463,6 +1572,15 @@ test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \
 @EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
 
 @EXPERIMENTAL_TRUE@tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@EXPERIMENTAL_TRUE@tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                            src/shared/util.h src/shared/util.c \
+@EXPERIMENTAL_TRUE@                            src/shared/mgmt.h src/shared/mgmt.c \
+@EXPERIMENTAL_TRUE@                            src/shared/hciemu.h src/shared/hciemu.c \
+@EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
+
+@EXPERIMENTAL_TRUE@tools_smp_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 @EXPERIMENTAL_TRUE@tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
 @EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
 @EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
@@ -1658,8 +1776,76 @@ obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src  \
 obexd_src_obexd_SHORTNAME = obexd
 obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist)
 nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files)
-@ANDROID_TRUE@android_bluetoothd_SOURCES = android/main.c src/log.c
-@ANDROID_TRUE@android_bluetoothd_LDADD = @GLIB_LIBS@
+@ANDROID_TRUE@android_system_emulator_SOURCES = android/system-emulator.c \
+@ANDROID_TRUE@                                 monitor/mainloop.h monitor/mainloop.c
+
+@ANDROID_TRUE@android_bluetoothd_SOURCES = android/main.c \
+@ANDROID_TRUE@                         src/log.c \
+@ANDROID_TRUE@                         android/hal-msg.h \
+@ANDROID_TRUE@                         android/utils.h \
+@ANDROID_TRUE@                         src/sdpd-database.c src/sdpd-server.c \
+@ANDROID_TRUE@                         src/sdpd-service.c src/sdpd-request.c \
+@ANDROID_TRUE@                         src/glib-helper.h src/glib-helper.c \
+@ANDROID_TRUE@                         src/eir.h src/eir.c \
+@ANDROID_TRUE@                         src/shared/util.h src/shared/util.c \
+@ANDROID_TRUE@                         src/shared/mgmt.h src/shared/mgmt.c \
+@ANDROID_TRUE@                         android/bluetooth.h android/bluetooth.c \
+@ANDROID_TRUE@                         android/hidhost.h android/hidhost.c \
+@ANDROID_TRUE@                         android/ipc.h android/ipc.c \
+@ANDROID_TRUE@                         android/a2dp.h android/a2dp.c \
+@ANDROID_TRUE@                         android/socket.h android/socket.c \
+@ANDROID_TRUE@                         android/pan.h android/pan.c \
+@ANDROID_TRUE@                         btio/btio.h btio/btio.c \
+@ANDROID_TRUE@                         src/sdp-client.h src/sdp-client.c
+
+@ANDROID_TRUE@android_bluetoothd_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@ANDROID_TRUE@android_libhal_internal_la_SOURCES = android/hal.h android/hal-bluetooth.c \
+@ANDROID_TRUE@                                 android/hal-sock.c \
+@ANDROID_TRUE@                                 android/hal-hidhost.c \
+@ANDROID_TRUE@                                 android/hal-pan.c \
+@ANDROID_TRUE@                                 android/hal-a2dp.c \
+@ANDROID_TRUE@                                 android/hardware/bluetooth.h \
+@ANDROID_TRUE@                                 android/hardware/bt_av.h \
+@ANDROID_TRUE@                                 android/hardware/bt_gatt.h \
+@ANDROID_TRUE@                                 android/hardware/bt_gatt_client.h \
+@ANDROID_TRUE@                                 android/hardware/bt_gatt_server.h \
+@ANDROID_TRUE@                                 android/hardware/bt_gatt_types.h \
+@ANDROID_TRUE@                                 android/hardware/bt_hf.h \
+@ANDROID_TRUE@                                 android/hardware/bt_hh.h \
+@ANDROID_TRUE@                                 android/hardware/bt_hl.h \
+@ANDROID_TRUE@                                 android/hardware/bt_pan.h \
+@ANDROID_TRUE@                                 android/hardware/bt_rc.h \
+@ANDROID_TRUE@                                 android/hardware/bt_sock.h \
+@ANDROID_TRUE@                                 android/hardware/hardware.h \
+@ANDROID_TRUE@                                 android/cutils/properties.h \
+@ANDROID_TRUE@                                 android/hal-log.h \
+@ANDROID_TRUE@                                 android/hal-ipc.h android/hal-ipc.c
+
+@ANDROID_TRUE@android_libhal_internal_la_CPPFLAGS = -I$(srcdir)/android
+@ANDROID_TRUE@android_haltest_SOURCES = android/client/haltest.c \
+@ANDROID_TRUE@                         android/client/pollhandler.h \
+@ANDROID_TRUE@                         android/client/pollhandler.c \
+@ANDROID_TRUE@                         android/client/terminal.h \
+@ANDROID_TRUE@                         android/client/terminal.c \
+@ANDROID_TRUE@                         android/client/history.h \
+@ANDROID_TRUE@                         android/client/history.c \
+@ANDROID_TRUE@                         android/client/tabcompletion.c \
+@ANDROID_TRUE@                         android/client/if-main.h \
+@ANDROID_TRUE@                         android/client/if-av.c \
+@ANDROID_TRUE@                         android/client/if-bt.c \
+@ANDROID_TRUE@                         android/client/if-gatt.c \
+@ANDROID_TRUE@                         android/client/if-hf.c \
+@ANDROID_TRUE@                         android/client/if-hh.c \
+@ANDROID_TRUE@                         android/client/if-pan.c \
+@ANDROID_TRUE@                         android/client/if-sock.c \
+@ANDROID_TRUE@                         android/client/hwmodule.c \
+@ANDROID_TRUE@                         android/hal-utils.h android/hal-utils.c
+
+@ANDROID_TRUE@android_haltest_LDADD = android/libhal-internal.la
+@ANDROID_TRUE@android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+@ANDROID_TRUE@                         -DPLATFORM_SDK_VERSION=19
+
+@ANDROID_TRUE@android_haltest_LDFLAGS = -pthread
 @HID2HCI_TRUE@rulesdir = @UDEV_DIR@/rules.d
 @HID2HCI_TRUE@rules_DATA = tools/97-hid2hci.rules
 @TEST_TRUE@testdir = $(pkglibdir)/test
@@ -1739,7 +1925,7 @@ all: $(BUILT_SOURCES) config.h
 .SUFFIXES: .c .lo .o .obj
 am--refresh: Makefile
        @:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/android/Makefile.am $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
            *$$dep*) \
@@ -1762,7 +1948,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
            echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
            cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
        esac;
-$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android:
+$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/android/Makefile.am:
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
        $(SHELL) ./config.status --recheck
@@ -1879,6 +2065,26 @@ clean-pluginLTLIBRARIES:
          echo "rm -f \"$${dir}/so_locations\""; \
          rm -f "$${dir}/so_locations"; \
        done
+android/$(am__dirstamp):
+       @$(MKDIR_P) android
+       @: > android/$(am__dirstamp)
+android/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) android/$(DEPDIR)
+       @: > android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-bluetooth.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-sock.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-hidhost.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-pan.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-a2dp.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/android_libhal_internal_la-hal-ipc.lo:  \
+       android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp)
+android/libhal-internal.la: $(android_libhal_internal_la_OBJECTS) $(android_libhal_internal_la_DEPENDENCIES) $(EXTRA_android_libhal_internal_la_DEPENDENCIES) android/$(am__dirstamp)
+       $(AM_V_CCLD)$(LINK) $(am_android_libhal_internal_la_rpath) $(android_libhal_internal_la_OBJECTS) $(android_libhal_internal_la_LIBADD) $(LIBS)
 gdbus/$(am__dirstamp):
        @$(MKDIR_P) gdbus
        @: > gdbus/$(am__dirstamp)
@@ -2110,12 +2316,6 @@ clean-udevPROGRAMS:
        list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
        echo " rm -f" $$list; \
        rm -f $$list
-android/$(am__dirstamp):
-       @$(MKDIR_P) android
-       @: > android/$(am__dirstamp)
-android/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) android/$(DEPDIR)
-       @: > android/$(DEPDIR)/$(am__dirstamp)
 android/main.$(OBJEXT): android/$(am__dirstamp) \
        android/$(DEPDIR)/$(am__dirstamp)
 src/$(am__dirstamp):
@@ -2125,9 +2325,115 @@ src/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) src/$(DEPDIR)
        @: > src/$(DEPDIR)/$(am__dirstamp)
 src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-database.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-server.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-service.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-request.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/glib-helper.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/eir.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/shared/$(am__dirstamp):
+       @$(MKDIR_P) src/shared
+       @: > src/shared/$(am__dirstamp)
+src/shared/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) src/shared/$(DEPDIR)
+       @: > src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/util.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/mgmt.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+android/bluetooth.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/hidhost.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/ipc.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/a2dp.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/socket.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/pan.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+btio/$(am__dirstamp):
+       @$(MKDIR_P) btio
+       @: > btio/$(am__dirstamp)
+btio/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) btio/$(DEPDIR)
+       @: > btio/$(DEPDIR)/$(am__dirstamp)
+btio/btio.$(OBJEXT): btio/$(am__dirstamp) \
+       btio/$(DEPDIR)/$(am__dirstamp)
+src/sdp-client.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
 android/bluetoothd$(EXEEXT): $(android_bluetoothd_OBJECTS) $(android_bluetoothd_DEPENDENCIES) $(EXTRA_android_bluetoothd_DEPENDENCIES) android/$(am__dirstamp)
        @rm -f android/bluetoothd$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(android_bluetoothd_OBJECTS) $(android_bluetoothd_LDADD) $(LIBS)
+android/client/$(am__dirstamp):
+       @$(MKDIR_P) android/client
+       @: > android/client/$(am__dirstamp)
+android/client/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) android/client/$(DEPDIR)
+       @: > android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-haltest.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-pollhandler.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-terminal.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-history.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-tabcompletion.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-av.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-bt.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-gatt.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-hf.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-hh.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-pan.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-if-sock.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/client/android_haltest-hwmodule.$(OBJEXT):  \
+       android/client/$(am__dirstamp) \
+       android/client/$(DEPDIR)/$(am__dirstamp)
+android/android_haltest-hal-utils.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+android/haltest$(EXEEXT): $(android_haltest_OBJECTS) $(android_haltest_DEPENDENCIES) $(EXTRA_android_haltest_DEPENDENCIES) android/$(am__dirstamp)
+       @rm -f android/haltest$(EXEEXT)
+       $(AM_V_CCLD)$(android_haltest_LINK) $(android_haltest_OBJECTS) $(android_haltest_LDADD) $(LIBS)
+android/system-emulator.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+monitor/$(am__dirstamp):
+       @$(MKDIR_P) monitor
+       @: > monitor/$(am__dirstamp)
+monitor/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) monitor/$(DEPDIR)
+       @: > monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/mainloop.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+android/system-emulator$(EXEEXT): $(android_system_emulator_OBJECTS) $(android_system_emulator_DEPENDENCIES) $(EXTRA_android_system_emulator_DEPENDENCIES) android/$(am__dirstamp)
+       @rm -f android/system-emulator$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(android_system_emulator_OBJECTS) $(android_system_emulator_LDADD) $(LIBS)
 attrib/$(am__dirstamp):
        @$(MKDIR_P) attrib
        @: > attrib/$(am__dirstamp)
@@ -2142,14 +2448,6 @@ attrib/gatt.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/gattrib.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
-btio/$(am__dirstamp):
-       @$(MKDIR_P) btio
-       @: > btio/$(am__dirstamp)
-btio/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) btio/$(DEPDIR)
-       @: > btio/$(DEPDIR)/$(am__dirstamp)
-btio/btio.$(OBJEXT): btio/$(am__dirstamp) \
-       btio/$(DEPDIR)/$(am__dirstamp)
 attrib/interactive.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/utils.$(OBJEXT): attrib/$(am__dirstamp) \
@@ -2169,12 +2467,6 @@ client/main.$(OBJEXT): client/$(am__dirstamp) \
        client/$(DEPDIR)/$(am__dirstamp)
 client/agent.$(OBJEXT): client/$(am__dirstamp) \
        client/$(DEPDIR)/$(am__dirstamp)
-monitor/$(am__dirstamp):
-       @$(MKDIR_P) monitor
-       @: > monitor/$(am__dirstamp)
-monitor/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) monitor/$(DEPDIR)
-       @: > monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/uuid.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
 client/bluetoothctl$(EXEEXT): $(client_bluetoothctl_OBJECTS) $(client_bluetoothctl_DEPENDENCIES) $(EXTRA_client_bluetoothctl_DEPENDENCIES) client/$(am__dirstamp)
@@ -2188,8 +2480,6 @@ emulator/$(DEPDIR)/$(am__dirstamp):
        @: > emulator/$(DEPDIR)/$(am__dirstamp)
 emulator/b1ee.$(OBJEXT): emulator/$(am__dirstamp) \
        emulator/$(DEPDIR)/$(am__dirstamp)
-monitor/mainloop.$(OBJEXT): monitor/$(am__dirstamp) \
-       monitor/$(DEPDIR)/$(am__dirstamp)
 emulator/b1ee$(EXEEXT): $(emulator_b1ee_OBJECTS) $(emulator_b1ee_DEPENDENCIES) $(EXTRA_emulator_b1ee_DEPENDENCIES) emulator/$(am__dirstamp)
        @rm -f emulator/b1ee$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(emulator_b1ee_OBJECTS) $(emulator_b1ee_LDADD) $(LIBS)
@@ -2649,12 +2939,6 @@ src/bluetoothd-dbus-common.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-eir.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/shared/$(am__dirstamp):
-       @$(MKDIR_P) src/shared
-       @: > src/shared/$(am__dirstamp)
-src/shared/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) src/shared/$(DEPDIR)
-       @: > src/shared/$(DEPDIR)/$(am__dirstamp)
 src/shared/bluetoothd-util.$(OBJEXT): src/shared/$(am__dirstamp) \
        src/shared/$(DEPDIR)/$(am__dirstamp)
 src/shared/bluetoothd-mgmt.$(OBJEXT): src/shared/$(am__dirstamp) \
@@ -2730,13 +3014,6 @@ tools/btiotest$(EXEEXT): $(tools_btiotest_OBJECTS) $(tools_btiotest_DEPENDENCIES
        $(AM_V_CCLD)$(LINK) $(tools_btiotest_OBJECTS) $(tools_btiotest_LDADD) $(LIBS)
 tools/btmgmt.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-src/glib-helper.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-src/eir.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
-src/shared/util.$(OBJEXT): src/shared/$(am__dirstamp) \
-       src/shared/$(DEPDIR)/$(am__dirstamp)
-src/shared/mgmt.$(OBJEXT): src/shared/$(am__dirstamp) \
-       src/shared/$(DEPDIR)/$(am__dirstamp)
 tools/btmgmt$(EXEEXT): $(tools_btmgmt_OBJECTS) $(tools_btmgmt_DEPENDENCIES) $(EXTRA_tools_btmgmt_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/btmgmt$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_btmgmt_OBJECTS) $(tools_btmgmt_LDADD) $(LIBS)
@@ -2953,6 +3230,11 @@ src/sdp-xml.$(OBJEXT): src/$(am__dirstamp) \
 tools/sdptool$(EXEEXT): $(tools_sdptool_OBJECTS) $(tools_sdptool_DEPENDENCIES) $(EXTRA_tools_sdptool_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/sdptool$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_sdptool_OBJECTS) $(tools_sdptool_LDADD) $(LIBS)
+tools/smp-tester.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/smp-tester$(EXEEXT): $(tools_smp_tester_OBJECTS) $(tools_smp_tester_DEPENDENCIES) $(EXTRA_tools_smp_tester_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/smp-tester$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_smp_tester_OBJECTS) $(tools_smp_tester_LDADD) $(LIBS)
 unit/$(am__dirstamp):
        @$(MKDIR_P) unit
        @: > unit/$(am__dirstamp)
@@ -3013,12 +3295,6 @@ unit/test-mgmt$(EXEEXT): $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_DEPENDENCIES
        $(AM_V_CCLD)$(LINK) $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_LDADD) $(LIBS)
 unit/test-sdp.$(OBJEXT): unit/$(am__dirstamp) \
        unit/$(DEPDIR)/$(am__dirstamp)
-src/sdpd-database.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-src/sdpd-service.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-src/sdpd-request.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
 unit/test-sdp$(EXEEXT): $(unit_test_sdp_OBJECTS) $(unit_test_sdp_DEPENDENCIES) $(EXTRA_unit_test_sdp_DEPENDENCIES) unit/$(am__dirstamp)
        @rm -f unit/test-sdp$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(unit_test_sdp_OBJECTS) $(unit_test_sdp_LDADD) $(LIBS)
@@ -3072,7 +3348,40 @@ uninstall-testSCRIPTS:
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
+       -rm -f android/a2dp.$(OBJEXT)
+       -rm -f android/android_haltest-hal-utils.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-a2dp.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-a2dp.lo
+       -rm -f android/android_libhal_internal_la-hal-bluetooth.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-bluetooth.lo
+       -rm -f android/android_libhal_internal_la-hal-hidhost.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-hidhost.lo
+       -rm -f android/android_libhal_internal_la-hal-ipc.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-ipc.lo
+       -rm -f android/android_libhal_internal_la-hal-pan.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-pan.lo
+       -rm -f android/android_libhal_internal_la-hal-sock.$(OBJEXT)
+       -rm -f android/android_libhal_internal_la-hal-sock.lo
+       -rm -f android/bluetooth.$(OBJEXT)
+       -rm -f android/client/android_haltest-haltest.$(OBJEXT)
+       -rm -f android/client/android_haltest-history.$(OBJEXT)
+       -rm -f android/client/android_haltest-hwmodule.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-av.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-bt.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-gatt.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-hf.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-hh.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-pan.$(OBJEXT)
+       -rm -f android/client/android_haltest-if-sock.$(OBJEXT)
+       -rm -f android/client/android_haltest-pollhandler.$(OBJEXT)
+       -rm -f android/client/android_haltest-tabcompletion.$(OBJEXT)
+       -rm -f android/client/android_haltest-terminal.$(OBJEXT)
+       -rm -f android/hidhost.$(OBJEXT)
+       -rm -f android/ipc.$(OBJEXT)
        -rm -f android/main.$(OBJEXT)
+       -rm -f android/pan.$(OBJEXT)
+       -rm -f android/socket.$(OBJEXT)
+       -rm -f android/system-emulator.$(OBJEXT)
        -rm -f attrib/att.$(OBJEXT)
        -rm -f attrib/bluetoothd-att.$(OBJEXT)
        -rm -f attrib/bluetoothd-gatt-service.$(OBJEXT)
@@ -3258,9 +3567,11 @@ mostlyclean-compile:
        -rm -f src/glib-helper.$(OBJEXT)
        -rm -f src/log.$(OBJEXT)
        -rm -f src/oui.$(OBJEXT)
+       -rm -f src/sdp-client.$(OBJEXT)
        -rm -f src/sdp-xml.$(OBJEXT)
        -rm -f src/sdpd-database.$(OBJEXT)
        -rm -f src/sdpd-request.$(OBJEXT)
+       -rm -f src/sdpd-server.$(OBJEXT)
        -rm -f src/sdpd-service.$(OBJEXT)
        -rm -f src/shared/bluetoothd-mgmt.$(OBJEXT)
        -rm -f src/shared/bluetoothd-util.$(OBJEXT)
@@ -3342,6 +3653,7 @@ mostlyclean-compile:
        -rm -f tools/sco-tester.$(OBJEXT)
        -rm -f tools/scotest.$(OBJEXT)
        -rm -f tools/sdptool.$(OBJEXT)
+       -rm -f tools/smp-tester.$(OBJEXT)
        -rm -f tools/ubcsp.$(OBJEXT)
        -rm -f unit/test-crc.$(OBJEXT)
        -rm -f unit/test-eir.$(OBJEXT)
@@ -3361,7 +3673,34 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/a2dp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_haltest-hal-utils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-a2dp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-bluetooth.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-hidhost.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-ipc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-pan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_libhal_internal_la-hal-sock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/hidhost.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/ipc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/pan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/socket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/system-emulator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-haltest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-history.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-hwmodule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-av.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-bt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-gatt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-hf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-pan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-if-sock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-pollhandler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-tabcompletion.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/android_haltest-terminal.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt-service.Po@am__quote@
@@ -3537,9 +3876,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/glib-helper.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/oui.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-xml.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-database.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-request.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-server.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-service.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/textfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/bluetoothd-mgmt.Po@am__quote@
@@ -3597,6 +3938,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sco-tester.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/scotest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sdptool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/smp-tester.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ubcsp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/amp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/att.Po@am__quote@
@@ -3661,6 +4003,48 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+android/android_libhal_internal_la-hal-bluetooth.lo: android/hal-bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-bluetooth.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-bluetooth.Tpo -c -o android/android_libhal_internal_la-hal-bluetooth.lo `test -f 'android/hal-bluetooth.c' || echo '$(srcdir)/'`android/hal-bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-bluetooth.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-bluetooth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-bluetooth.c' object='android/android_libhal_internal_la-hal-bluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-bluetooth.lo `test -f 'android/hal-bluetooth.c' || echo '$(srcdir)/'`android/hal-bluetooth.c
+
+android/android_libhal_internal_la-hal-sock.lo: android/hal-sock.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-sock.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-sock.Tpo -c -o android/android_libhal_internal_la-hal-sock.lo `test -f 'android/hal-sock.c' || echo '$(srcdir)/'`android/hal-sock.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-sock.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-sock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-sock.c' object='android/android_libhal_internal_la-hal-sock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-sock.lo `test -f 'android/hal-sock.c' || echo '$(srcdir)/'`android/hal-sock.c
+
+android/android_libhal_internal_la-hal-hidhost.lo: android/hal-hidhost.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-hidhost.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-hidhost.Tpo -c -o android/android_libhal_internal_la-hal-hidhost.lo `test -f 'android/hal-hidhost.c' || echo '$(srcdir)/'`android/hal-hidhost.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-hidhost.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-hidhost.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-hidhost.c' object='android/android_libhal_internal_la-hal-hidhost.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-hidhost.lo `test -f 'android/hal-hidhost.c' || echo '$(srcdir)/'`android/hal-hidhost.c
+
+android/android_libhal_internal_la-hal-pan.lo: android/hal-pan.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-pan.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-pan.Tpo -c -o android/android_libhal_internal_la-hal-pan.lo `test -f 'android/hal-pan.c' || echo '$(srcdir)/'`android/hal-pan.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-pan.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-pan.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-pan.c' object='android/android_libhal_internal_la-hal-pan.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-pan.lo `test -f 'android/hal-pan.c' || echo '$(srcdir)/'`android/hal-pan.c
+
+android/android_libhal_internal_la-hal-a2dp.lo: android/hal-a2dp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-a2dp.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-a2dp.Tpo -c -o android/android_libhal_internal_la-hal-a2dp.lo `test -f 'android/hal-a2dp.c' || echo '$(srcdir)/'`android/hal-a2dp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-a2dp.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-a2dp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-a2dp.c' object='android/android_libhal_internal_la-hal-a2dp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-a2dp.lo `test -f 'android/hal-a2dp.c' || echo '$(srcdir)/'`android/hal-a2dp.c
+
+android/android_libhal_internal_la-hal-ipc.lo: android/hal-ipc.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_libhal_internal_la-hal-ipc.lo -MD -MP -MF android/$(DEPDIR)/android_libhal_internal_la-hal-ipc.Tpo -c -o android/android_libhal_internal_la-hal-ipc.lo `test -f 'android/hal-ipc.c' || echo '$(srcdir)/'`android/hal-ipc.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_libhal_internal_la-hal-ipc.Tpo android/$(DEPDIR)/android_libhal_internal_la-hal-ipc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-ipc.c' object='android/android_libhal_internal_la-hal-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_libhal_internal_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_libhal_internal_la-hal-ipc.lo `test -f 'android/hal-ipc.c' || echo '$(srcdir)/'`android/hal-ipc.c
+
 plugins/plugins_external_dummy_la-external-dummy.lo: plugins/external-dummy.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -MT plugins/plugins_external_dummy_la-external-dummy.lo -MD -MP -MF plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo
@@ -3668,6 +4052,202 @@ plugins/plugins_external_dummy_la-external-dummy.lo: plugins/external-dummy.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
 
+android/client/android_haltest-haltest.o: android/client/haltest.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-haltest.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-haltest.Tpo -c -o android/client/android_haltest-haltest.o `test -f 'android/client/haltest.c' || echo '$(srcdir)/'`android/client/haltest.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-haltest.Tpo android/client/$(DEPDIR)/android_haltest-haltest.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/haltest.c' object='android/client/android_haltest-haltest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-haltest.o `test -f 'android/client/haltest.c' || echo '$(srcdir)/'`android/client/haltest.c
+
+android/client/android_haltest-haltest.obj: android/client/haltest.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-haltest.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-haltest.Tpo -c -o android/client/android_haltest-haltest.obj `if test -f 'android/client/haltest.c'; then $(CYGPATH_W) 'android/client/haltest.c'; else $(CYGPATH_W) '$(srcdir)/android/client/haltest.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-haltest.Tpo android/client/$(DEPDIR)/android_haltest-haltest.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/haltest.c' object='android/client/android_haltest-haltest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-haltest.obj `if test -f 'android/client/haltest.c'; then $(CYGPATH_W) 'android/client/haltest.c'; else $(CYGPATH_W) '$(srcdir)/android/client/haltest.c'; fi`
+
+android/client/android_haltest-pollhandler.o: android/client/pollhandler.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-pollhandler.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-pollhandler.Tpo -c -o android/client/android_haltest-pollhandler.o `test -f 'android/client/pollhandler.c' || echo '$(srcdir)/'`android/client/pollhandler.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-pollhandler.Tpo android/client/$(DEPDIR)/android_haltest-pollhandler.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/pollhandler.c' object='android/client/android_haltest-pollhandler.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-pollhandler.o `test -f 'android/client/pollhandler.c' || echo '$(srcdir)/'`android/client/pollhandler.c
+
+android/client/android_haltest-pollhandler.obj: android/client/pollhandler.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-pollhandler.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-pollhandler.Tpo -c -o android/client/android_haltest-pollhandler.obj `if test -f 'android/client/pollhandler.c'; then $(CYGPATH_W) 'android/client/pollhandler.c'; else $(CYGPATH_W) '$(srcdir)/android/client/pollhandler.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-pollhandler.Tpo android/client/$(DEPDIR)/android_haltest-pollhandler.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/pollhandler.c' object='android/client/android_haltest-pollhandler.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-pollhandler.obj `if test -f 'android/client/pollhandler.c'; then $(CYGPATH_W) 'android/client/pollhandler.c'; else $(CYGPATH_W) '$(srcdir)/android/client/pollhandler.c'; fi`
+
+android/client/android_haltest-terminal.o: android/client/terminal.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-terminal.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-terminal.Tpo -c -o android/client/android_haltest-terminal.o `test -f 'android/client/terminal.c' || echo '$(srcdir)/'`android/client/terminal.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-terminal.Tpo android/client/$(DEPDIR)/android_haltest-terminal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/terminal.c' object='android/client/android_haltest-terminal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-terminal.o `test -f 'android/client/terminal.c' || echo '$(srcdir)/'`android/client/terminal.c
+
+android/client/android_haltest-terminal.obj: android/client/terminal.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-terminal.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-terminal.Tpo -c -o android/client/android_haltest-terminal.obj `if test -f 'android/client/terminal.c'; then $(CYGPATH_W) 'android/client/terminal.c'; else $(CYGPATH_W) '$(srcdir)/android/client/terminal.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-terminal.Tpo android/client/$(DEPDIR)/android_haltest-terminal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/terminal.c' object='android/client/android_haltest-terminal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-terminal.obj `if test -f 'android/client/terminal.c'; then $(CYGPATH_W) 'android/client/terminal.c'; else $(CYGPATH_W) '$(srcdir)/android/client/terminal.c'; fi`
+
+android/client/android_haltest-history.o: android/client/history.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-history.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-history.Tpo -c -o android/client/android_haltest-history.o `test -f 'android/client/history.c' || echo '$(srcdir)/'`android/client/history.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-history.Tpo android/client/$(DEPDIR)/android_haltest-history.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/history.c' object='android/client/android_haltest-history.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-history.o `test -f 'android/client/history.c' || echo '$(srcdir)/'`android/client/history.c
+
+android/client/android_haltest-history.obj: android/client/history.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-history.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-history.Tpo -c -o android/client/android_haltest-history.obj `if test -f 'android/client/history.c'; then $(CYGPATH_W) 'android/client/history.c'; else $(CYGPATH_W) '$(srcdir)/android/client/history.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-history.Tpo android/client/$(DEPDIR)/android_haltest-history.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/history.c' object='android/client/android_haltest-history.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-history.obj `if test -f 'android/client/history.c'; then $(CYGPATH_W) 'android/client/history.c'; else $(CYGPATH_W) '$(srcdir)/android/client/history.c'; fi`
+
+android/client/android_haltest-tabcompletion.o: android/client/tabcompletion.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-tabcompletion.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-tabcompletion.Tpo -c -o android/client/android_haltest-tabcompletion.o `test -f 'android/client/tabcompletion.c' || echo '$(srcdir)/'`android/client/tabcompletion.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-tabcompletion.Tpo android/client/$(DEPDIR)/android_haltest-tabcompletion.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/tabcompletion.c' object='android/client/android_haltest-tabcompletion.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-tabcompletion.o `test -f 'android/client/tabcompletion.c' || echo '$(srcdir)/'`android/client/tabcompletion.c
+
+android/client/android_haltest-tabcompletion.obj: android/client/tabcompletion.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-tabcompletion.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-tabcompletion.Tpo -c -o android/client/android_haltest-tabcompletion.obj `if test -f 'android/client/tabcompletion.c'; then $(CYGPATH_W) 'android/client/tabcompletion.c'; else $(CYGPATH_W) '$(srcdir)/android/client/tabcompletion.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-tabcompletion.Tpo android/client/$(DEPDIR)/android_haltest-tabcompletion.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/tabcompletion.c' object='android/client/android_haltest-tabcompletion.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-tabcompletion.obj `if test -f 'android/client/tabcompletion.c'; then $(CYGPATH_W) 'android/client/tabcompletion.c'; else $(CYGPATH_W) '$(srcdir)/android/client/tabcompletion.c'; fi`
+
+android/client/android_haltest-if-av.o: android/client/if-av.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-av.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-av.Tpo -c -o android/client/android_haltest-if-av.o `test -f 'android/client/if-av.c' || echo '$(srcdir)/'`android/client/if-av.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-av.Tpo android/client/$(DEPDIR)/android_haltest-if-av.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-av.c' object='android/client/android_haltest-if-av.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-av.o `test -f 'android/client/if-av.c' || echo '$(srcdir)/'`android/client/if-av.c
+
+android/client/android_haltest-if-av.obj: android/client/if-av.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-av.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-av.Tpo -c -o android/client/android_haltest-if-av.obj `if test -f 'android/client/if-av.c'; then $(CYGPATH_W) 'android/client/if-av.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-av.Tpo android/client/$(DEPDIR)/android_haltest-if-av.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-av.c' object='android/client/android_haltest-if-av.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-av.obj `if test -f 'android/client/if-av.c'; then $(CYGPATH_W) 'android/client/if-av.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av.c'; fi`
+
+android/client/android_haltest-if-bt.o: android/client/if-bt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-bt.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-bt.Tpo -c -o android/client/android_haltest-if-bt.o `test -f 'android/client/if-bt.c' || echo '$(srcdir)/'`android/client/if-bt.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-bt.Tpo android/client/$(DEPDIR)/android_haltest-if-bt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-bt.c' object='android/client/android_haltest-if-bt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-bt.o `test -f 'android/client/if-bt.c' || echo '$(srcdir)/'`android/client/if-bt.c
+
+android/client/android_haltest-if-bt.obj: android/client/if-bt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-bt.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-bt.Tpo -c -o android/client/android_haltest-if-bt.obj `if test -f 'android/client/if-bt.c'; then $(CYGPATH_W) 'android/client/if-bt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-bt.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-bt.Tpo android/client/$(DEPDIR)/android_haltest-if-bt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-bt.c' object='android/client/android_haltest-if-bt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-bt.obj `if test -f 'android/client/if-bt.c'; then $(CYGPATH_W) 'android/client/if-bt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-bt.c'; fi`
+
+android/client/android_haltest-if-gatt.o: android/client/if-gatt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-gatt.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-gatt.Tpo -c -o android/client/android_haltest-if-gatt.o `test -f 'android/client/if-gatt.c' || echo '$(srcdir)/'`android/client/if-gatt.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-gatt.Tpo android/client/$(DEPDIR)/android_haltest-if-gatt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-gatt.c' object='android/client/android_haltest-if-gatt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-gatt.o `test -f 'android/client/if-gatt.c' || echo '$(srcdir)/'`android/client/if-gatt.c
+
+android/client/android_haltest-if-gatt.obj: android/client/if-gatt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-gatt.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-gatt.Tpo -c -o android/client/android_haltest-if-gatt.obj `if test -f 'android/client/if-gatt.c'; then $(CYGPATH_W) 'android/client/if-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-gatt.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-gatt.Tpo android/client/$(DEPDIR)/android_haltest-if-gatt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-gatt.c' object='android/client/android_haltest-if-gatt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-gatt.obj `if test -f 'android/client/if-gatt.c'; then $(CYGPATH_W) 'android/client/if-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-gatt.c'; fi`
+
+android/client/android_haltest-if-hf.o: android/client/if-hf.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-hf.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-hf.Tpo -c -o android/client/android_haltest-if-hf.o `test -f 'android/client/if-hf.c' || echo '$(srcdir)/'`android/client/if-hf.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-hf.Tpo android/client/$(DEPDIR)/android_haltest-if-hf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-hf.c' object='android/client/android_haltest-if-hf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-hf.o `test -f 'android/client/if-hf.c' || echo '$(srcdir)/'`android/client/if-hf.c
+
+android/client/android_haltest-if-hf.obj: android/client/if-hf.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-hf.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-hf.Tpo -c -o android/client/android_haltest-if-hf.obj `if test -f 'android/client/if-hf.c'; then $(CYGPATH_W) 'android/client/if-hf.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-hf.Tpo android/client/$(DEPDIR)/android_haltest-if-hf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-hf.c' object='android/client/android_haltest-if-hf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-hf.obj `if test -f 'android/client/if-hf.c'; then $(CYGPATH_W) 'android/client/if-hf.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf.c'; fi`
+
+android/client/android_haltest-if-hh.o: android/client/if-hh.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-hh.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-hh.Tpo -c -o android/client/android_haltest-if-hh.o `test -f 'android/client/if-hh.c' || echo '$(srcdir)/'`android/client/if-hh.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-hh.Tpo android/client/$(DEPDIR)/android_haltest-if-hh.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-hh.c' object='android/client/android_haltest-if-hh.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-hh.o `test -f 'android/client/if-hh.c' || echo '$(srcdir)/'`android/client/if-hh.c
+
+android/client/android_haltest-if-hh.obj: android/client/if-hh.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-hh.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-hh.Tpo -c -o android/client/android_haltest-if-hh.obj `if test -f 'android/client/if-hh.c'; then $(CYGPATH_W) 'android/client/if-hh.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hh.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-hh.Tpo android/client/$(DEPDIR)/android_haltest-if-hh.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-hh.c' object='android/client/android_haltest-if-hh.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-hh.obj `if test -f 'android/client/if-hh.c'; then $(CYGPATH_W) 'android/client/if-hh.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hh.c'; fi`
+
+android/client/android_haltest-if-pan.o: android/client/if-pan.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-pan.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-pan.Tpo -c -o android/client/android_haltest-if-pan.o `test -f 'android/client/if-pan.c' || echo '$(srcdir)/'`android/client/if-pan.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-pan.Tpo android/client/$(DEPDIR)/android_haltest-if-pan.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-pan.c' object='android/client/android_haltest-if-pan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-pan.o `test -f 'android/client/if-pan.c' || echo '$(srcdir)/'`android/client/if-pan.c
+
+android/client/android_haltest-if-pan.obj: android/client/if-pan.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-pan.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-pan.Tpo -c -o android/client/android_haltest-if-pan.obj `if test -f 'android/client/if-pan.c'; then $(CYGPATH_W) 'android/client/if-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-pan.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-pan.Tpo android/client/$(DEPDIR)/android_haltest-if-pan.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-pan.c' object='android/client/android_haltest-if-pan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-pan.obj `if test -f 'android/client/if-pan.c'; then $(CYGPATH_W) 'android/client/if-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-pan.c'; fi`
+
+android/client/android_haltest-if-sock.o: android/client/if-sock.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-sock.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-sock.Tpo -c -o android/client/android_haltest-if-sock.o `test -f 'android/client/if-sock.c' || echo '$(srcdir)/'`android/client/if-sock.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-sock.Tpo android/client/$(DEPDIR)/android_haltest-if-sock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-sock.c' object='android/client/android_haltest-if-sock.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-sock.o `test -f 'android/client/if-sock.c' || echo '$(srcdir)/'`android/client/if-sock.c
+
+android/client/android_haltest-if-sock.obj: android/client/if-sock.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-if-sock.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-if-sock.Tpo -c -o android/client/android_haltest-if-sock.obj `if test -f 'android/client/if-sock.c'; then $(CYGPATH_W) 'android/client/if-sock.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sock.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-if-sock.Tpo android/client/$(DEPDIR)/android_haltest-if-sock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/if-sock.c' object='android/client/android_haltest-if-sock.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-if-sock.obj `if test -f 'android/client/if-sock.c'; then $(CYGPATH_W) 'android/client/if-sock.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sock.c'; fi`
+
+android/client/android_haltest-hwmodule.o: android/client/hwmodule.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-hwmodule.o -MD -MP -MF android/client/$(DEPDIR)/android_haltest-hwmodule.Tpo -c -o android/client/android_haltest-hwmodule.o `test -f 'android/client/hwmodule.c' || echo '$(srcdir)/'`android/client/hwmodule.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-hwmodule.Tpo android/client/$(DEPDIR)/android_haltest-hwmodule.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/hwmodule.c' object='android/client/android_haltest-hwmodule.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-hwmodule.o `test -f 'android/client/hwmodule.c' || echo '$(srcdir)/'`android/client/hwmodule.c
+
+android/client/android_haltest-hwmodule.obj: android/client/hwmodule.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/client/android_haltest-hwmodule.obj -MD -MP -MF android/client/$(DEPDIR)/android_haltest-hwmodule.Tpo -c -o android/client/android_haltest-hwmodule.obj `if test -f 'android/client/hwmodule.c'; then $(CYGPATH_W) 'android/client/hwmodule.c'; else $(CYGPATH_W) '$(srcdir)/android/client/hwmodule.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/android_haltest-hwmodule.Tpo android/client/$(DEPDIR)/android_haltest-hwmodule.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/client/hwmodule.c' object='android/client/android_haltest-hwmodule.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/client/android_haltest-hwmodule.obj `if test -f 'android/client/hwmodule.c'; then $(CYGPATH_W) 'android/client/hwmodule.c'; else $(CYGPATH_W) '$(srcdir)/android/client/hwmodule.c'; fi`
+
+android/android_haltest-hal-utils.o: android/hal-utils.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/android_haltest-hal-utils.o -MD -MP -MF android/$(DEPDIR)/android_haltest-hal-utils.Tpo -c -o android/android_haltest-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_haltest-hal-utils.Tpo android/$(DEPDIR)/android_haltest-hal-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-utils.c' object='android/android_haltest-hal-utils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/android_haltest-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c
+
+android/android_haltest-hal-utils.obj: android/hal-utils.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -MT android/android_haltest-hal-utils.obj -MD -MP -MF android/$(DEPDIR)/android_haltest-hal-utils.Tpo -c -o android/android_haltest-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_haltest-hal-utils.Tpo android/$(DEPDIR)/android_haltest-hal-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='android/hal-utils.c' object='android/android_haltest-hal-utils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_haltest_CFLAGS) $(CFLAGS) -c -o android/android_haltest-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi`
+
 btio/obexd-btio.o: btio/btio.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT btio/obexd-btio.o -MD -MP -MF btio/$(DEPDIR)/obexd-btio.Tpo -c -o btio/obexd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) btio/$(DEPDIR)/obexd-btio.Tpo btio/$(DEPDIR)/obexd-btio.Po
@@ -6028,6 +6608,8 @@ distclean-generic:
        -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
        -rm -f android/$(DEPDIR)/$(am__dirstamp)
        -rm -f android/$(am__dirstamp)
+       -rm -f android/client/$(DEPDIR)/$(am__dirstamp)
+       -rm -f android/client/$(am__dirstamp)
        -rm -f attrib/$(DEPDIR)/$(am__dirstamp)
        -rm -f attrib/$(am__dirstamp)
        -rm -f btio/$(DEPDIR)/$(am__dirstamp)
@@ -6111,7 +6693,7 @@ clean-am: clean-binPROGRAMS clean-cupsPROGRAMS clean-generic \
 
 distclean: distclean-am
        -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-       -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
+       -rm -rf android/$(DEPDIR) android/client/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
        -rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
        distclean-hdr distclean-libtool distclean-tags
@@ -6166,7 +6748,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
        -rm -f $(am__CONFIG_DISTCLEAN_FILES)
        -rm -rf $(top_srcdir)/autom4te.cache
-       -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
+       -rm -rf android/$(DEPDIR) android/client/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
index 840b95c..78034f5 100644 (file)
@@ -33,7 +33,8 @@ endif
 if EXPERIMENTAL
 noinst_PROGRAMS += emulator/btvirt emulator/b1ee \
                                        tools/mgmt-tester tools/gap-tester \
-                                       tools/l2cap-tester tools/sco-tester
+                                       tools/l2cap-tester tools/sco-tester \
+                                       tools/smp-tester
 
 emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
                                        monitor/mainloop.h monitor/mainloop.c \
@@ -63,6 +64,15 @@ tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
                                src/shared/tester.h src/shared/tester.c
 tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
+tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
+                               emulator/btdev.h emulator/btdev.c \
+                               emulator/bthost.h emulator/bthost.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c \
+                               src/shared/hciemu.h src/shared/hciemu.c \
+                               src/shared/tester.h src/shared/tester.c
+tools_smp_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
 tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
                                emulator/btdev.h emulator/btdev.c \
                                emulator/bthost.h emulator/bthost.c \
index 0e025ac..616a338 100644 (file)
@@ -6,6 +6,13 @@ BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D
 # Specify pathmap for glib
 pathmap_INCL += glib:external/bluetooth/glib
 
+# Specify common compiler flags
+BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
+       -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
+
+# Disable warnings enabled by Android but not enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wno-pointer-arith -Wno-missing-field-initializers
+
 #
 # Android BlueZ daemon (bluetoothd)
 #
@@ -14,18 +21,55 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
        main.c \
-       log.c \
+       bluetooth.c \
+       hidhost.c \
+       socket.c \
+       ipc.c ipc.h \
+       a2dp.c \
+       pan.c \
+       ../src/log.c \
+       ../src/shared/mgmt.c \
+       ../src/shared/util.c \
+       ../src/sdpd-database.c \
+       ../src/sdpd-service.c \
+       ../src/sdpd-request.c \
+       ../src/sdpd-server.c \
+       ../src/glib-helper.c \
+       ../src/eir.c \
+       ../lib/sdp.c \
+       ../lib/bluetooth.c \
+       ../lib/hci.c \
+       ../btio/btio.c \
+       ../src/sdp-client.c \
 
 LOCAL_C_INCLUDES := \
        $(call include-path-for, glib) \
        $(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+       $(LOCAL_PATH)/../ \
        $(LOCAL_PATH)/../src \
+       $(LOCAL_PATH)/../lib \
 
-LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_SHARED_LIBRARIES := \
        libglib \
 
+lib_headers := \
+       bluetooth.h \
+       hci.h \
+       hci_lib.h \
+       l2cap.h \
+       sdp_lib.h \
+       sdp.h \
+       rfcomm.h \
+       sco.h \
+
+$(shell mkdir -p $(LOCAL_PATH)/../lib/bluetooth)
+
+$(foreach file,$(lib_headers), $(shell ln -sf ../$(file) $(LOCAL_PATH)/../lib/bluetooth/$(file)))
+
 LOCAL_MODULE := bluetoothd
 
 include $(BUILD_EXECUTABLE)
@@ -37,15 +81,122 @@ include $(BUILD_EXECUTABLE)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
-       hal_bluetooth.c \
-       hal_bt_sock.c \
+       hal-ipc.c \
+       hal-bluetooth.c \
+       hal-sock.c \
+       hal-hidhost.c \
+       hal-pan.c \
+       hal-a2dp.c \
+       hal-utils.c \
+
+LOCAL_C_INCLUDES += \
+       $(call include-path-for, system-core) \
+       $(call include-path-for, libhardware) \
 
 LOCAL_SHARED_LIBRARIES := \
        libcutils \
 
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) \
+
 LOCAL_MODULE := bluetooth.default
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_REQUIRED_MODULES := haltest bluetoothd
 
 include $(BUILD_SHARED_LIBRARY)
+
+#
+# haltest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       client/haltest.c \
+       client/pollhandler.c \
+       client/terminal.c \
+       client/history.c \
+       client/tabcompletion.c \
+       client/if-av.c \
+       client/if-bt.c \
+       client/if-hf.c \
+       client/if-hh.c \
+       client/if-pan.c \
+       client/if-sock.c \
+       hal-utils.c \
+
+ANDROID_4_3_OR_ABOVE := $(shell echo 0 | awk -v v=$(PLATFORM_SDK_VERSION) 'END {print (v > 17) ? 1 : 0}')
+
+ifeq ($(ANDROID_4_3_OR_ABOVE), 1)
+LOCAL_SRC_FILES += \
+       client/if-gatt.c
+endif
+
+LOCAL_C_INCLUDES += \
+       $(call include-path-for, system-core) \
+       $(call include-path-for, libhardware) \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := libhardware
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := haltest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# btmon
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       ../monitor/main.c \
+       ../monitor/bt.h \
+       ../monitor/mainloop.h \
+       ../monitor/mainloop.c \
+       ../monitor/display.h \
+       ../monitor/display.c \
+       ../monitor/hcidump.h \
+       ../monitor/hcidump.c \
+       ../monitor/btsnoop.h \
+       ../monitor/btsnoop.c \
+       ../monitor/control.h \
+       ../monitor/control.c \
+       ../monitor/packet.h \
+       ../monitor/packet.c \
+       ../monitor/l2cap.h \
+       ../monitor/l2cap.c \
+       ../monitor/uuid.h \
+       ../monitor/uuid.c \
+       ../monitor/sdp.h \
+       ../monitor/sdp.c \
+       ../monitor/vendor.h \
+       ../monitor/vendor.c \
+       ../monitor/lmp.h \
+       ../monitor/lmp.c \
+       ../monitor/crc.h \
+       ../monitor/crc.c \
+       ../monitor/ll.h \
+       ../monitor/ll.c \
+       ../lib/hci.c \
+       ../lib/bluetooth.c \
+
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/.. \
+       $(LOCAL_PATH)/../lib \
+       $(LOCAL_PATH)/../src/shared \
+
+LOCAL_C_INCLUDES += \
+       $(call include-path-for, glib) \
+       $(call include-path-for, glib)/glib \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := btmon
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/Makefile.am b/android/Makefile.am
new file mode 100644 (file)
index 0000000..4e0c9ed
--- /dev/null
@@ -0,0 +1,86 @@
+if ANDROID
+noinst_PROGRAMS += android/system-emulator
+
+android_system_emulator_SOURCES = android/system-emulator.c \
+                                       monitor/mainloop.h monitor/mainloop.c
+
+noinst_PROGRAMS += android/bluetoothd
+
+android_bluetoothd_SOURCES = android/main.c \
+                               src/log.c \
+                               android/hal-msg.h \
+                               android/utils.h \
+                               src/sdpd-database.c src/sdpd-server.c \
+                               src/sdpd-service.c src/sdpd-request.c \
+                               src/glib-helper.h src/glib-helper.c \
+                               src/eir.h src/eir.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c \
+                               android/bluetooth.h android/bluetooth.c \
+                               android/hidhost.h android/hidhost.c \
+                               android/ipc.h android/ipc.c \
+                               android/a2dp.h android/a2dp.c \
+                               android/socket.h android/socket.c \
+                               android/pan.h android/pan.c \
+                               btio/btio.h btio/btio.c \
+                               src/sdp-client.h src/sdp-client.c
+
+android_bluetoothd_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+noinst_LTLIBRARIES += android/libhal-internal.la
+
+android_libhal_internal_la_SOURCES = android/hal.h android/hal-bluetooth.c \
+                                       android/hal-sock.c \
+                                       android/hal-hidhost.c \
+                                       android/hal-pan.c \
+                                       android/hal-a2dp.c \
+                                       android/hardware/bluetooth.h \
+                                       android/hardware/bt_av.h \
+                                       android/hardware/bt_gatt.h \
+                                       android/hardware/bt_gatt_client.h \
+                                       android/hardware/bt_gatt_server.h \
+                                       android/hardware/bt_gatt_types.h \
+                                       android/hardware/bt_hf.h \
+                                       android/hardware/bt_hh.h \
+                                       android/hardware/bt_hl.h \
+                                       android/hardware/bt_pan.h \
+                                       android/hardware/bt_rc.h \
+                                       android/hardware/bt_sock.h \
+                                       android/hardware/hardware.h \
+                                       android/cutils/properties.h \
+                                       android/hal-log.h \
+                                       android/hal-ipc.h android/hal-ipc.c
+
+android_libhal_internal_la_CPPFLAGS = -I$(srcdir)/android
+
+noinst_PROGRAMS += android/haltest
+
+android_haltest_SOURCES = android/client/haltest.c \
+                               android/client/pollhandler.h \
+                               android/client/pollhandler.c \
+                               android/client/terminal.h \
+                               android/client/terminal.c \
+                               android/client/history.h \
+                               android/client/history.c \
+                               android/client/tabcompletion.c \
+                               android/client/if-main.h \
+                               android/client/if-av.c \
+                               android/client/if-bt.c \
+                               android/client/if-gatt.c \
+                               android/client/if-hf.c \
+                               android/client/if-hh.c \
+                               android/client/if-pan.c \
+                               android/client/if-sock.c \
+                               android/client/hwmodule.c \
+                               android/hal-utils.h android/hal-utils.c
+
+android_haltest_LDADD = android/libhal-internal.la
+
+android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+                               -DPLATFORM_SDK_VERSION=19
+
+android_haltest_LDFLAGS = -pthread
+
+endif
+
+EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README
diff --git a/android/README b/android/README
new file mode 100644 (file)
index 0000000..6c2c53f
--- /dev/null
@@ -0,0 +1,90 @@
+BlueZ for Android
+*****************
+
+Since Android 4.2 there exists a well standardized HAL interface that the
+Bluetooth stack is expected to provide and which enables the easy replacement
+of the stack of choice on Android. Android BlueZ is intended as a drop-in
+replacement to Android provided Bluetooth stack.
+
+More details about BlueZ for Android architecture and components can be found
+in android/hal-apc-api.txt file.
+
+===============================
+Building and running on Android
+===============================
+
+Build requirements
+==================
+
+- GLib - Android 4.2 or later don't provide GLib and one must provide it in
+'external/bluetooth/glib' folder of Android tree. Sample Android GLib port
+is available at https://code.google.com/p/android-bluez.glib/
+
+- Bionic support - BlueZ requires signalfd and timerfd APIs to be provided
+by libc library. Currently only 'master' branch available at
+https://android.googlesource.com/platform/bionic provides all required
+functionality and running BlueZ on older branch requires backporting missing
+features. Sample Bionic for Android on Intel Architecture (Android-IA) with all
+required features backported is available at
+https://code.google.com/p/android-bluez.bionic/
+
+Runtime requirements
+====================
+
+BlueZ HAL library requires 'bluetoothd' service to be available on Android
+system. This can be done by defining service in init.rc file of targeted board:
+
+service bluetoothd /system/bin/logwrapper /system/bin/bluetoothd
+  class main
+  group bluetooth net_admin
+  disabled
+  oneshot
+
+It is required that bluetooth user could start and stop bluetoothd service by
+setting 'ctl.start' or 'ctl.stop' property. This can be achieved by
+whitelisting bluetooth user and bluetoothd service in init source code.
+
+Required Android init system modifications can be found at
+https://code.google.com/p/android-bluez.system-core/
+
+Downloading and building
+========================
+
+Building for Android requires full Android AOSP source tree. Sample Android-IA
+tree with all required components present is available at
+http://code.google.com/p/android-bluez/
+
+Downloading:
+repo init -u https://code.google.com/p/android-bluez.manifest/ -m topics/bluez
+repo sync
+
+Build for Intel ultrabook:
+'source build/envsetup.sh'
+'lunch core_mesa-eng'
+'make allimages -j8'
+
+After full build is done it is possible to rebuild only BlueZ:
+'cd external/bluetooth/bluez/android/'
+'mm' (or 'mm -B' to force rebuilding of all files)
+'adb sync' to update target device.
+
+=============================
+Building and running on Linux
+=============================
+
+It is possible to build and test BlueZ for Android daemon on Linux (eg. PC).
+Simply follow instructions available at README file in BlueZ top directory.
+Android daemon binary is located at android/bluetoothd. See next section on
+how to test Android daemon on Linux.
+
+============
+Testing tool
+============
+
+BT HAL test tools located in android/haltest is provided for HAL level testing
+of both Android daemon and HAL library. Start it and type 'adapter init' in
+prompt to initialize HAL library. On Android required bluetoothd service will
+be started automatically. On Linux it is required to start android/bluetoothd
+manually before init command timeout. To deinitialize HAL library and stop
+daemon type 'adapter cleanup'. Type 'help' for more information. Tab completion
+is also supported.
diff --git a/android/a2dp.c b/android/a2dp.c
new file mode 100644 (file)
index 0000000..936c28e
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "btio/btio.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "log.h"
+#include "a2dp.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "utils.h"
+#include "bluetooth.h"
+
+#define L2CAP_PSM_AVDTP 0x19
+#define SVC_HINT_CAPTURING 0x08
+
+static int notification_sk = -1;
+static GIOChannel *server = NULL;
+static GSList *devices = NULL;
+static bdaddr_t adapter_addr;
+static uint32_t record_id = 0;
+
+struct a2dp_device {
+       bdaddr_t        dst;
+       uint8_t         state;
+       GIOChannel      *io;
+       guint           watch;
+};
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+       const struct a2dp_device *dev = s;
+       const bdaddr_t *dst = user_data;
+
+       return bacmp(&dev->dst, dst);
+}
+
+static void a2dp_device_free(struct a2dp_device *dev)
+{
+       if (dev->watch > 0)
+               g_source_remove(dev->watch);
+
+       if (dev->io)
+               g_io_channel_unref(dev->io);
+
+       devices = g_slist_remove(devices, dev);
+       g_free(dev);
+}
+
+static struct a2dp_device *a2dp_device_new(const bdaddr_t *dst)
+{
+       struct a2dp_device *dev;
+
+       dev = g_new0(struct a2dp_device, 1);
+       bacpy(&dev->dst, dst);
+       devices = g_slist_prepend(devices, dev);
+
+       return dev;
+}
+
+static void bt_a2dp_notify_state(struct a2dp_device *dev, uint8_t state)
+{
+       struct hal_ev_a2dp_conn_state ev;
+       char address[18];
+
+       if (dev->state == state)
+               return;
+
+       dev->state = state;
+
+       ba2str(&dev->dst, address);
+       DBG("device %s state %u", address, state);
+
+       bdaddr2android(&dev->dst, ev.bdaddr);
+       ev.state = state;
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_A2DP,
+                       HAL_EV_A2DP_CONN_STATE, sizeof(ev), &ev, -1);
+}
+
+static gboolean watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+       struct a2dp_device *dev = data;
+
+       bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+
+       a2dp_device_free(dev);
+
+       return FALSE;
+}
+
+static void signaling_connect_cb(GIOChannel *chan, GError *err,
+                                                       gpointer user_data)
+{
+       struct a2dp_device *dev = user_data;
+
+       if (err) {
+               bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+               error("%s", err->message);
+               a2dp_device_free(dev);
+               return;
+       }
+
+       dev->watch = g_io_add_watch(dev->io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                                               watch_cb, dev);
+
+       bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTED);
+}
+
+static uint8_t bt_a2dp_connect(struct hal_cmd_a2dp_connect *cmd, uint16_t len)
+{
+       struct a2dp_device *dev;
+       char addr[18];
+       bdaddr_t dst;
+       GSList *l;
+       GError *err = NULL;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (l)
+               return HAL_STATUS_FAILED;
+
+       dev = a2dp_device_new(&dst);
+       dev->io = bt_io_connect(signaling_connect_cb, dev, NULL, &err,
+                                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                                       BT_IO_OPT_DEST_BDADDR, &dev->dst,
+                                       BT_IO_OPT_PSM, L2CAP_PSM_AVDTP,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                                       BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               a2dp_device_free(dev);
+               return HAL_STATUS_FAILED;
+       }
+
+       ba2str(&dev->dst, addr);
+       DBG("connecting to %s", addr);
+
+       bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_a2dp_disconnect(struct hal_cmd_a2dp_connect *cmd,
+                                                               uint16_t len)
+{
+       struct a2dp_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       /* Wait signaling channel to HUP */
+       if (dev->io)
+               g_io_channel_shutdown(dev->io, TRUE, NULL);
+
+       bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTING);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+void bt_a2dp_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
+{
+       uint8_t status = HAL_STATUS_FAILED;
+
+       switch (opcode) {
+       case HAL_OP_A2DP_CONNECT:
+               status = bt_a2dp_connect(buf, len);
+               break;
+       case HAL_OP_A2DP_DISCONNECT:
+               status = bt_a2dp_disconnect(buf, len);
+               break;
+       default:
+               DBG("Unhandled command, opcode 0x%x", opcode);
+               break;
+       }
+
+       ipc_send_rsp(sk, HAL_SERVICE_ID_A2DP, status);
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+       struct a2dp_device *dev;
+       bdaddr_t src, dst;
+       char address[18];
+       GError *gerr = NULL;
+       GSList *l;
+
+       if (err) {
+               error("%s", err->message);
+               return;
+       }
+
+       bt_io_get(chan, &gerr,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               return;
+       }
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (l)
+               return;
+
+       ba2str(&dst, address);
+       DBG("Incoming connection from %s", address);
+
+       dev = a2dp_device_new(&dst);
+       signaling_connect_cb(chan, err, dev);
+}
+
+static sdp_record_t *a2dp_record(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+       uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto, *proto[2];
+       sdp_record_t *record;
+       sdp_data_t *psm, *version, *features;
+       uint16_t lp = AVDTP_UUID;
+       uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f;
+
+       record = sdp_record_alloc();
+       if (!record)
+               return NULL;
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &a2dp_uuid);
+       sdp_set_service_classes(record, svclass_id);
+
+       sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
+       profile[0].version = a2dp_ver;
+       pfseq = sdp_list_append(0, &profile[0]);
+       sdp_set_profile_descs(record, pfseq);
+
+       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+       proto[0] = sdp_list_append(0, &l2cap_uuid);
+       psm = sdp_data_alloc(SDP_UINT16, &lp);
+       proto[0] = sdp_list_append(proto[0], psm);
+       apseq = sdp_list_append(0, proto[0]);
+
+       sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
+       proto[1] = sdp_list_append(0, &avdtp_uuid);
+       version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
+       proto[1] = sdp_list_append(proto[1], version);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       features = sdp_data_alloc(SDP_UINT16, &feat);
+       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+       sdp_set_info_attr(record, "Audio Source", 0, 0);
+
+       free(psm);
+       free(version);
+       sdp_list_free(proto[0], 0);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(pfseq, 0);
+       sdp_list_free(aproto, 0);
+       sdp_list_free(root, 0);
+       sdp_list_free(svclass_id, 0);
+
+       return record;
+}
+
+bool bt_a2dp_register(int sk, const bdaddr_t *addr)
+{
+       GError *err = NULL;
+       sdp_record_t *rec;
+
+       DBG("");
+
+       bacpy(&adapter_addr, addr);
+
+       server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                               BT_IO_OPT_PSM, L2CAP_PSM_AVDTP,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_INVALID);
+       if (!server) {
+               error("Failed to listen on AVDTP channel: %s", err->message);
+               g_error_free(err);
+               return false;
+       }
+
+       rec = a2dp_record();
+       if (bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
+               error("Failed to register on A2DP record");
+               sdp_record_free(rec);
+               g_io_channel_shutdown(server, TRUE, NULL);
+               g_io_channel_unref(server);
+               server = NULL;
+               return false;
+       }
+       record_id = rec->handle;
+
+       notification_sk = sk;
+
+       return true;
+}
+
+void bt_a2dp_unregister(void)
+{
+       DBG("");
+
+       notification_sk = -1;
+
+       bt_adapter_remove_record(record_id);
+       record_id = 0;
+
+       if (server) {
+               g_io_channel_shutdown(server, TRUE, NULL);
+               g_io_channel_unref(server);
+               server = NULL;
+       }
+}
diff --git a/android/a2dp.h b/android/a2dp.h
new file mode 100644 (file)
index 0000000..3531618
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void bt_a2dp_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
+
+bool bt_a2dp_register(int sk, const bdaddr_t *addr);
+void bt_a2dp_unregister(void);
diff --git a/android/bluetooth.c b/android/bluetooth.c
new file mode 100644 (file)
index 0000000..83f20e2
--- /dev/null
@@ -0,0 +1,2313 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/mgmt.h"
+#include "src/shared/mgmt.h"
+#include "src/glib-helper.h"
+#include "src/eir.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "src/sdp-client.h"
+#include "src/sdpd.h"
+#include "log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "utils.h"
+#include "bluetooth.h"
+
+#define DEVICE_ID_SOURCE       0x0002  /* USB */
+#define DEVICE_ID_VENDOR       0x1d6b  /* Linux Foundation */
+#define DEVICE_ID_PRODUCT      0x0247  /* BlueZ for Android */
+
+/* Default to DisplayYesNo */
+#define DEFAULT_IO_CAPABILITY 0x01
+/* Default discoverable timeout 120sec as in Android */
+#define DEFAULT_DISCOVERABLE_TIMEOUT 120
+
+#define BASELEN_PROP_CHANGED (sizeof(struct hal_ev_adapter_props_changed) \
+                               + (sizeof(struct hal_property)))
+
+static uint16_t option_index = MGMT_INDEX_NONE;
+
+static int notification_sk = -1;
+
+#define BASELEN_REMOTE_DEV_PROP (sizeof(struct hal_ev_remote_device_props) \
+                                       + sizeof(struct hal_property))
+/* This list contains addresses which are asked for records */
+static GSList *browse_reqs;
+
+static struct mgmt *mgmt_if = NULL;
+
+static struct {
+       uint16_t index;
+
+       bdaddr_t bdaddr;
+       uint32_t dev_class;
+
+       char *name;
+
+       uint32_t current_settings;
+
+       bool discovering;
+       uint32_t discoverable_timeout;
+
+       GSList *uuids;
+} adapter = {
+       .index = MGMT_INDEX_NONE,
+       .dev_class = 0,
+       .name = NULL,
+       .current_settings = 0,
+       .discovering = false,
+       .discoverable_timeout = DEFAULT_DISCOVERABLE_TIMEOUT,
+       .uuids = NULL,
+};
+
+struct device {
+       bdaddr_t bdaddr;
+       int bond_state;
+       char *name;
+};
+
+struct browse_req {
+       bdaddr_t bdaddr;
+       GSList *uuids;
+       int search_uuid;
+       int reconnect_attempt;
+};
+
+static const uint16_t uuid_list[] = {
+       L2CAP_UUID,
+       PNP_INFO_SVCLASS_ID,
+       PUBLIC_BROWSE_GROUP,
+       0
+};
+
+static GSList *found_devices = NULL;
+static GSList *devices = NULL;
+
+static void adapter_name_changed(const uint8_t *name)
+{
+       struct hal_ev_adapter_props_changed *ev;
+       size_t len = strlen((const char *) name);
+       uint8_t buf[BASELEN_PROP_CHANGED + len];
+
+       memset(buf, 0, sizeof(buf));
+       ev = (void *) buf;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+       ev->props[0].type = HAL_PROP_ADAPTER_NAME;
+       /* Android expects value without NULL terminator */
+       ev->props[0].len = len;
+       memcpy(ev->props->val, name, len);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), ev, -1);
+}
+
+static void adapter_set_name(const uint8_t *name)
+{
+       if (!g_strcmp0(adapter.name, (const char *) name))
+               return;
+
+       DBG("%s", name);
+
+       g_free(adapter.name);
+       adapter.name = g_strdup((const char *) name);
+
+       adapter_name_changed(name);
+}
+
+static void mgmt_local_name_changed_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_cp_set_local_name *rp = param;
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of local name changed parameters");
+               return;
+       }
+
+       adapter_set_name(rp->name);
+
+       /* TODO Update services if needed */
+}
+
+static void powered_changed(void)
+{
+       struct hal_ev_adapter_state_changed ev;
+
+       ev.state = (adapter.current_settings & MGMT_SETTING_POWERED) ?
+                                               HAL_POWER_ON : HAL_POWER_OFF;
+
+       DBG("%u", ev.state);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_STATE_CHANGED, sizeof(ev), &ev, -1);
+}
+
+static uint8_t settings2scan_mode(void)
+{
+       bool connectable, discoverable;
+
+       connectable = adapter.current_settings & MGMT_SETTING_CONNECTABLE;
+       discoverable = adapter.current_settings & MGMT_SETTING_DISCOVERABLE;
+
+       if (connectable && discoverable)
+               return HAL_ADAPTER_SCAN_MODE_CONN_DISC;
+
+       if (connectable)
+               return HAL_ADAPTER_SCAN_MODE_CONN;
+
+       return HAL_ADAPTER_SCAN_MODE_NONE;
+}
+
+static void scan_mode_changed(void)
+{
+       uint8_t buf[BASELEN_PROP_CHANGED + 1];
+       struct hal_ev_adapter_props_changed *ev = (void *) buf;
+       uint8_t *mode;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+
+       ev->props[0].type = HAL_PROP_ADAPTER_SCAN_MODE;
+       ev->props[0].len = 1;
+
+       mode = ev->props[0].val;
+       *mode = settings2scan_mode();
+
+       DBG("mode %u", *mode);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), buf, -1);
+}
+
+static void adapter_class_changed(void)
+{
+       uint8_t buf[BASELEN_PROP_CHANGED + sizeof(uint32_t)];
+       struct hal_ev_adapter_props_changed *ev = (void *) buf;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+
+       ev->props[0].type = HAL_PROP_ADAPTER_CLASS;
+       ev->props[0].len = sizeof(uint32_t);
+       memcpy(ev->props->val, &adapter.dev_class, sizeof(uint32_t));
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), buf, -1);
+}
+
+static void settings_changed(uint32_t settings)
+{
+       uint32_t changed_mask;
+       uint32_t scan_mode_mask;
+
+       changed_mask = adapter.current_settings ^ settings;
+
+       adapter.current_settings = settings;
+
+       DBG("0x%08x", changed_mask);
+
+       if (changed_mask & MGMT_SETTING_POWERED)
+               powered_changed();
+
+
+       scan_mode_mask = MGMT_SETTING_CONNECTABLE |
+                                       MGMT_SETTING_DISCOVERABLE;
+
+       /*
+        * Only when powered, the connectable and discoverable
+        * state changes should be communicated.
+        */
+       if (adapter.current_settings & MGMT_SETTING_POWERED)
+               if (changed_mask & scan_mode_mask)
+                       scan_mode_changed();
+}
+
+static void new_settings_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       uint32_t settings;
+
+       if (length < sizeof(settings)) {
+               error("Wrong size of new settings parameters");
+               return;
+       }
+
+       settings = bt_get_le32(param);
+
+       DBG("settings: 0x%8.8x -> 0x%8.8x", adapter.current_settings,
+                                                               settings);
+
+       if (settings == adapter.current_settings)
+               return;
+
+       settings_changed(settings);
+}
+
+static void mgmt_dev_class_changed_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_cod *rp = param;
+       uint32_t dev_class;
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of class of device changed parameters");
+               return;
+       }
+
+       dev_class = rp->val[0] | (rp->val[1] << 8) | (rp->val[2] << 16);
+
+       if (dev_class == adapter.dev_class)
+               return;
+
+       DBG("Class: 0x%06x", dev_class);
+
+       adapter.dev_class = dev_class;
+
+       adapter_class_changed();
+
+       /* TODO: Gatt attrib set*/
+}
+
+static void store_link_key(const bdaddr_t *dst, const uint8_t *key,
+                                       uint8_t type, uint8_t pin_length)
+{
+       /* TODO store link key */
+
+}
+
+static int bdaddr_cmp(gconstpointer a, gconstpointer b)
+{
+       const bdaddr_t *bda = a;
+       const bdaddr_t *bdb = b;
+
+       return bacmp(bdb, bda);
+}
+
+static void send_bond_state_change(const bdaddr_t *addr, uint8_t status,
+                                                               uint8_t state)
+{
+       struct hal_ev_bond_state_changed ev;
+
+       ev.status = status;
+       ev.state = state;
+       bdaddr2android(addr, ev.bdaddr);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_BOND_STATE_CHANGED, sizeof(ev), &ev, -1);
+}
+
+static void cache_device_name(const bdaddr_t *addr, const char *name)
+{
+       struct device *dev = NULL;
+       GSList *l;
+
+       l = g_slist_find_custom(devices, addr, bdaddr_cmp);
+       if (l)
+               dev = l->data;
+
+       if (!dev) {
+               dev = g_new0(struct device, 1);
+               bacpy(&dev->bdaddr, addr);
+               dev->bond_state = HAL_BOND_STATE_NONE;
+               devices = g_slist_prepend(devices, dev);
+       }
+
+       if (!g_strcmp0(dev->name, name))
+               return;
+
+       g_free(dev->name);
+       dev->name = g_strdup(name);
+       /*TODO: Do some real caching here */
+}
+
+static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
+                                                               int state) {
+
+       struct device *dev = NULL;
+       GSList *l;
+
+       l = g_slist_find_custom(devices, addr, bdaddr_cmp);
+       if (l)
+               dev = l->data;
+
+       if (!dev) {
+               dev = g_new0(struct device, 1);
+               bacpy(&dev->bdaddr, addr);
+               dev->bond_state = HAL_BOND_STATE_NONE;
+               devices = g_slist_prepend(devices, dev);
+       }
+
+       if (dev->bond_state != state) {
+               dev->bond_state = state;
+               send_bond_state_change(&dev->bdaddr, status, state);
+       }
+}
+
+static void browse_req_free(struct browse_req *req)
+{
+       g_slist_free_full(req->uuids, g_free);
+       g_free(req);
+}
+
+static void fill_uuids(GSList *list, void *buf)
+{
+       for (; list; list = g_slist_next(list)) {
+               memcpy(buf, list->data, sizeof(uint128_t));
+               buf += sizeof(uint128_t);
+       }
+}
+
+static void remote_uuids_callback(struct browse_req *req)
+{
+       struct hal_ev_remote_device_props *ev;
+       int len;
+
+       len = sizeof(*ev) + sizeof(struct hal_property) + (sizeof(uint128_t) *
+                                               g_slist_length(req->uuids));
+       ev = g_malloc(len);
+
+       ev->status = HAL_STATUS_SUCCESS;
+       bdaddr2android(&req->bdaddr, &ev->bdaddr);
+       ev->num_props = 1;
+       ev->props[0].type = HAL_PROP_DEVICE_UUIDS;
+       ev->props[0].len = sizeof(uint128_t) * g_slist_length(req->uuids);
+       fill_uuids(req->uuids, ev->props[0].val);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                               HAL_EV_REMOTE_DEVICE_PROPS, len, ev, -1);
+
+       g_free(ev);
+}
+
+static int uuid_128_cmp(gconstpointer a, gconstpointer b)
+{
+       return memcmp(a, b, sizeof(uint128_t));
+}
+
+static void update_records(struct browse_req *req, sdp_list_t *recs)
+{
+       for (; recs; recs = recs->next) {
+               sdp_record_t *rec = (sdp_record_t *) recs->data;
+               sdp_list_t *svcclass = NULL;
+               uuid_t uuid128;
+               uuid_t *tmp;
+               uint8_t *new_uuid;
+
+               if (!rec)
+                       break;
+
+               if (sdp_get_service_classes(rec, &svcclass) < 0)
+                       continue;
+
+               if (!svcclass)
+                       continue;
+
+               tmp = svcclass->data;
+
+               switch (tmp->type) {
+               case SDP_UUID16:
+                       sdp_uuid16_to_uuid128(&uuid128, tmp);
+                       break;
+               case SDP_UUID32:
+                       sdp_uuid32_to_uuid128(&uuid128, tmp);
+                       break;
+               case SDP_UUID128:
+                       memcpy(&uuid128, tmp, sizeof(uuid_t));
+                       break;
+               default:
+                       continue;
+               }
+
+               new_uuid = g_malloc(16);/* size of 128 bit uuid */
+               memcpy(new_uuid, &uuid128.value.uuid128,
+                               sizeof(uuid128.value.uuid128));
+
+               /* Check if uuid is already added */
+               if (g_slist_find_custom(req->uuids, new_uuid, uuid_128_cmp))
+                       g_free(new_uuid);
+               else
+                       req->uuids = g_slist_append(req->uuids, new_uuid);
+
+               sdp_list_free(svcclass, free);
+       }
+}
+
+static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+       struct browse_req *req = user_data;
+       uuid_t uuid;
+
+       /* If we have a valid response and req->search_uuid == 2, then L2CAP
+        * UUID & PNP searching was successful -- we are done */
+       if (err < 0 || req->search_uuid == 2) {
+               if (err == -ECONNRESET && req->reconnect_attempt < 1) {
+                       req->search_uuid--;
+                       req->reconnect_attempt++;
+               } else {
+                       goto done;
+               }
+       }
+
+       update_records(req, recs);
+
+       /* Search for mandatory uuids */
+       if (uuid_list[req->search_uuid]) {
+               sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
+               bt_search_service(&adapter.bdaddr, &req->bdaddr, &uuid,
+                                               browse_cb, user_data, NULL);
+               return;
+       }
+
+done:
+       remote_uuids_callback(req);
+
+       browse_reqs = g_slist_remove(browse_reqs, req);
+       browse_req_free(req);
+}
+
+static int req_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct browse_req *req = a;
+       const bdaddr_t *bdaddr = b;
+
+       return bacmp(&req->bdaddr, bdaddr);
+}
+
+static uint8_t browse_remote_sdp(const bdaddr_t *addr)
+{
+       struct browse_req *req;
+       uuid_t uuid;
+
+       if (g_slist_find_custom(browse_reqs, addr, req_cmp))
+               return HAL_STATUS_DONE;
+
+       req = g_new0(struct browse_req, 1);
+       bacpy(&req->bdaddr, addr);
+       sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
+
+       if (bt_search_service(&adapter.bdaddr,
+                       &req->bdaddr, &uuid, browse_cb, req, NULL) < 0) {
+               browse_req_free(req);
+               return false;
+       }
+
+       browse_reqs = g_slist_append(browse_reqs, req);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static void new_link_key_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_new_link_key *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small new link key event");
+               return;
+       }
+
+       ba2str(&addr->bdaddr, dst);
+
+       DBG("new key for %s type %u pin_len %u",
+                                       dst, ev->key.type, ev->key.pin_len);
+
+       if (ev->key.pin_len > 16) {
+               error("Invalid PIN length (%u) in new_key event",
+                                                       ev->key.pin_len);
+               return;
+       }
+
+       if (ev->store_hint) {
+               const struct mgmt_link_key_info *key = &ev->key;
+
+               store_link_key(&addr->bdaddr, key->val, key->type,
+                                                               key->pin_len);
+       }
+
+       set_device_bond_state(&addr->bdaddr, HAL_STATUS_SUCCESS,
+                                                       HAL_BOND_STATE_BONDED);
+
+       browse_remote_sdp(&addr->bdaddr);
+}
+
+static const char *get_device_name(const bdaddr_t *addr)
+{
+       GSList *l;
+
+       l = g_slist_find_custom(devices, addr, bdaddr_cmp);
+       if (l) {
+               struct device *dev = l->data;
+               return dev->name;
+       }
+
+       return NULL;
+}
+
+static void send_remote_device_name_prop(const bdaddr_t *bdaddr)
+{
+       struct hal_ev_remote_device_props *ev;
+       const char *name;
+       size_t ev_len;
+       char dst[18];
+
+       /* Use cached name or bdaddr string */
+       name = get_device_name(bdaddr);
+       if (!name)
+               name = dst;
+
+       ev_len = BASELEN_REMOTE_DEV_PROP + strlen(name);
+       ev = g_malloc0(ev_len);
+
+       ev->status = HAL_STATUS_SUCCESS;
+       bdaddr2android(bdaddr, ev->bdaddr);
+       ev->num_props = 1;
+       ev->props[0].type = HAL_PROP_DEVICE_NAME;
+       ev->props[0].len = strlen(name);
+       memcpy(&ev->props[0].val, name, strlen(name));
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_REMOTE_DEVICE_PROPS, sizeof(ev), ev, -1);
+
+       g_free(ev);
+}
+
+static void pin_code_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_pin_code_request *ev = param;
+       struct hal_ev_pin_request hal_ev;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small PIN code request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, dst);
+
+       /* Workaround for Android Bluetooth.apk issue: send remote
+        * device property */
+       send_remote_device_name_prop(&ev->addr.bdaddr);
+
+       set_device_bond_state(&ev->addr.bdaddr, HAL_STATUS_SUCCESS,
+                                               HAL_BOND_STATE_BONDING);
+
+       DBG("%s type %u secure %u", dst, ev->addr.type, ev->secure);
+
+       /* TODO CoD of remote devices should probably be cached
+        * Name we already send in remote device prop */
+       memset(&hal_ev, 0, sizeof(hal_ev));
+       bdaddr2android(&ev->addr.bdaddr, hal_ev.bdaddr);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH, HAL_EV_PIN_REQUEST,
+                                               sizeof(hal_ev), &hal_ev, -1);
+}
+
+static void send_ssp_request(const bdaddr_t *addr, uint8_t variant,
+                                                       uint32_t passkey)
+{
+       struct hal_ev_ssp_request ev;
+
+       /* It is ok to have empty name and CoD of remote devices here since
+       * those information has been already provided on device_connected event
+       * or during device scaning. Android will use that instead.
+       */
+       memset(&ev, 0, sizeof(ev));
+       bdaddr2android(addr, ev.bdaddr);
+       ev.pairing_variant = variant;
+       ev.passkey = passkey;
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH, HAL_EV_SSP_REQUEST,
+                                                       sizeof(ev), &ev, -1);
+}
+
+static void user_confirm_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_user_confirm_request *ev = param;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small user confirm request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, dst);
+       DBG("%s confirm_hint %u", dst, ev->confirm_hint);
+
+       set_device_bond_state(&ev->addr.bdaddr, HAL_STATUS_SUCCESS,
+                                               HAL_BOND_STATE_BONDING);
+
+       if (ev->confirm_hint)
+               send_ssp_request(&ev->addr.bdaddr, HAL_SSP_VARIANT_CONSENT, 0);
+       else
+               send_ssp_request(&ev->addr.bdaddr, HAL_SSP_VARIANT_CONFIRM,
+                                                               ev->value);
+}
+
+static void user_passkey_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_user_passkey_request *ev = param;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small passkey request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, dst);
+       DBG("%s", dst);
+
+       set_device_bond_state(&ev->addr.bdaddr, HAL_STATUS_SUCCESS,
+                                               HAL_BOND_STATE_BONDING);
+
+       send_ssp_request(&ev->addr.bdaddr, HAL_SSP_VARIANT_ENTRY, 0);
+}
+
+static void user_passkey_notify_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_passkey_notify *ev = param;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small passkey notify event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, dst);
+       DBG("%s entered %u", dst, ev->entered);
+
+       /* HAL seems to not support entered characters */
+       if (ev->entered)
+               return;
+
+       set_device_bond_state(&ev->addr.bdaddr, HAL_STATUS_SUCCESS,
+                                               HAL_BOND_STATE_BONDING);
+
+       send_ssp_request(&ev->addr.bdaddr, HAL_SSP_VARIANT_NOTIF,
+                                                               ev->passkey);
+}
+
+static void mgmt_discovering_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_discovering *ev = param;
+       struct hal_ev_discovery_state_changed cp;
+
+       if (length < sizeof(*ev)) {
+               error("Too small discovering event");
+               return;
+       }
+
+       DBG("hci%u type %u discovering %u", index, ev->type,
+                                                       ev->discovering);
+
+       if (adapter.discovering == !!ev->discovering)
+               return;
+
+       adapter.discovering = !!ev->discovering;
+
+       DBG("new discovering state %u", ev->discovering);
+
+       if (adapter.discovering) {
+               cp.state = HAL_DISCOVERY_STATE_STARTED;
+       } else {
+               g_slist_free_full(found_devices, g_free);
+               found_devices = NULL;
+
+               cp.state = HAL_DISCOVERY_STATE_STOPPED;
+       }
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_DISCOVERY_STATE_CHANGED, sizeof(cp), &cp, -1);
+}
+
+static void confirm_device_name(const bdaddr_t *addr, uint8_t addr_type)
+{
+       struct mgmt_cp_confirm_name cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, addr);
+       cp.addr.type = addr_type;
+
+       if (mgmt_reply(mgmt_if, MGMT_OP_CONFIRM_NAME, adapter.index,
+                               sizeof(cp), &cp, NULL, NULL, NULL) == 0)
+               error("Failed to send confirm name request");
+}
+
+static int fill_device_props(struct hal_property *prop, bdaddr_t *addr,
+                                       uint32_t cod, int8_t rssi, char *name)
+{
+       uint8_t num_props = 0;
+
+       /* fill Class of Device */
+       if (cod) {
+               prop->type = HAL_PROP_DEVICE_CLASS;
+               prop->len = sizeof(cod);
+               memcpy(prop->val, &cod, prop->len);
+               prop = ((void *) prop) + sizeof(*prop) + sizeof(cod);
+               num_props++;
+       }
+
+       /* fill RSSI */
+       if (rssi) {
+               prop->type = HAL_PROP_DEVICE_RSSI;
+               prop->len = sizeof(rssi);
+               memcpy(prop->val, &rssi, prop->len);
+               prop = ((void *) prop) + sizeof(*prop) + sizeof(rssi);
+               num_props++;
+       }
+
+       /* fill name */
+       if (name) {
+               prop->type = HAL_PROP_DEVICE_NAME;
+               prop->len = strlen(name);
+               memcpy(prop->val, name, prop->len);
+               prop = ((void *) prop) + sizeof(*prop) + prop->len;
+               num_props++;
+       }
+
+       return num_props;
+}
+
+static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                       int8_t rssi, bool confirm,
+                                       const uint8_t *data, uint8_t data_len)
+{
+       bool is_new_dev = false;
+       size_t props_size = 0;
+       size_t buff_size = 0;
+       void *buf;
+       struct eir_data eir;
+       GSList *l;
+       bdaddr_t *remote = NULL;
+       int err;
+
+       memset(&eir, 0, sizeof(eir));
+
+       err = eir_parse(&eir, data, data_len);
+       if (err < 0) {
+               error("Error parsing EIR data: %s (%d)", strerror(-err), -err);
+               return;
+       }
+
+       l = g_slist_find_custom(found_devices, bdaddr, bdaddr_cmp);
+       if (l)
+               remote = l->data;
+
+       if (!remote) {
+               char addr[18];
+
+               remote = g_new0(bdaddr_t, 1);
+               bacpy(remote, bdaddr);
+
+               found_devices = g_slist_prepend(found_devices, remote);
+               is_new_dev = true;
+
+               ba2str(remote, addr);
+               DBG("New device found: %s", addr);
+       }
+
+       props_size += sizeof(struct hal_property) + sizeof(eir.class);
+       props_size += sizeof(struct hal_property) + sizeof(rssi);
+
+       if (eir.name) {
+               props_size += sizeof(struct hal_property) + strlen(eir.name);
+               cache_device_name(remote, eir.name);
+       }
+
+       if (is_new_dev) {
+               struct hal_ev_device_found *ev = NULL;
+               struct hal_property *prop = NULL;
+
+               /* with new device we also send bdaddr prop */
+               props_size += sizeof(struct hal_property) + sizeof(eir.addr);
+
+               buff_size = sizeof(struct hal_ev_device_found) + props_size;
+               buf = g_new0(char, buff_size);
+               ev = buf;
+               prop = ev->props;
+
+               /* fill first prop with bdaddr */
+               prop->type = HAL_PROP_DEVICE_ADDR;
+               prop->len = sizeof(bdaddr_t);
+               bdaddr2android(bdaddr, prop->val);
+               prop = ((void *) prop) + sizeof(*prop) + sizeof(bdaddr_t);
+               ev->num_props += 1;
+
+               /* fill eir, name, and cod props */
+               ev->num_props += fill_device_props(prop, remote, eir.class,
+                                                               rssi, eir.name);
+
+               ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                               HAL_EV_DEVICE_FOUND, buff_size, ev, -1);
+               g_free(buf);
+       } else {
+               struct hal_ev_remote_device_props *ev = NULL;
+
+               buff_size = sizeof(*ev) + props_size;
+               buf = g_new0(char, buff_size);
+               ev = buf;
+
+               ev->num_props = fill_device_props(ev->props, remote, eir.class,
+                                                               rssi, eir.name);
+
+               ev->status = HAL_STATUS_SUCCESS;
+               bdaddr2android(bdaddr, ev->bdaddr);
+
+               ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                               HAL_EV_REMOTE_DEVICE_PROPS, buff_size, ev, -1);
+               g_free(buf);
+       }
+
+       if (confirm) {
+               char addr[18];
+
+               ba2str(bdaddr, addr);
+               info("Device %s needs name confirmation.", addr);
+               confirm_device_name(bdaddr, bdaddr_type);
+       }
+
+       eir_data_free(&eir);
+}
+
+static void mgmt_device_found_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_found *ev = param;
+       const uint8_t *eir;
+       uint16_t eir_len;
+       uint32_t flags;
+       bool confirm_name;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too short device found event (%u bytes)", length);
+               return;
+       }
+
+       eir_len = btohs(ev->eir_len);
+       if (length != sizeof(*ev) + eir_len) {
+               error("Device found event size mismatch (%u != %zu)",
+                                       length, sizeof(*ev) + eir_len);
+               return;
+       }
+
+       if (eir_len == 0)
+               eir = NULL;
+       else
+               eir = ev->eir;
+
+       flags = btohl(ev->flags);
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u eir %u",
+                               index, addr, ev->rssi, flags, eir_len, *eir);
+
+       confirm_name = flags & MGMT_DEV_FOUND_CONFIRM_NAME;
+
+       update_found_device(&ev->addr.bdaddr, ev->addr.type, ev->rssi,
+                                               confirm_name, eir, eir_len);
+}
+
+static void mgmt_device_connected_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_connected *ev = param;
+       struct hal_ev_acl_state_changed hal_ev;
+
+       if (length < sizeof(*ev)) {
+               error("Too short device connected event (%u bytes)", length);
+               return;
+       }
+
+       update_found_device(&ev->addr.bdaddr, ev->addr.type, 0, false,
+                                       &ev->eir[0], btohs(ev->eir_len));
+
+       hal_ev.status = HAL_STATUS_SUCCESS;
+       hal_ev.state = HAL_ACL_STATE_CONNECTED;
+       bdaddr2android(&ev->addr.bdaddr, hal_ev.bdaddr);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ACL_STATE_CHANGED, sizeof(hal_ev), &hal_ev, -1);
+}
+
+static void mgmt_device_disconnected_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_disconnected *ev = param;
+       struct hal_ev_acl_state_changed hal_ev;
+
+       if (length < sizeof(*ev)) {
+               error("Too short device disconnected event (%u bytes)", length);
+               return;
+       }
+
+       hal_ev.status = HAL_STATUS_SUCCESS;
+       hal_ev.state = HAL_ACL_STATE_DISCONNECTED;
+       bdaddr2android(&ev->addr.bdaddr, hal_ev.bdaddr);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ACL_STATE_CHANGED, sizeof(hal_ev), &hal_ev, -1);
+}
+
+static uint8_t status_mgmt2hal(uint8_t mgmt)
+{
+       switch (mgmt) {
+       case MGMT_STATUS_SUCCESS:
+               return HAL_STATUS_SUCCESS;
+       case MGMT_STATUS_NO_RESOURCES:
+               return HAL_STATUS_NOMEM;
+       case MGMT_STATUS_BUSY:
+               return HAL_STATUS_BUSY;
+       case MGMT_STATUS_NOT_SUPPORTED:
+               return HAL_STATUS_UNSUPPORTED;
+       case MGMT_STATUS_INVALID_PARAMS:
+               return HAL_STATUS_INVALID;
+       case MGMT_STATUS_AUTH_FAILED:
+               return HAL_STATUS_AUTH_FAILURE;
+       case MGMT_STATUS_NOT_CONNECTED:
+               return HAL_STATUS_REMOTE_DEVICE_DOWN;
+       default:
+               return HAL_STATUS_FAILED;
+       }
+}
+
+static void mgmt_connect_failed_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_connect_failed *ev = param;
+
+       DBG("");
+
+       /* In case security mode 3 pairing we will get connect failed event
+       * in case e.g wrong PIN code entered. Let's check if device is
+       * bonding, if so update bond state */
+       set_device_bond_state(&ev->addr.bdaddr, status_mgmt2hal(ev->status),
+                                                       HAL_BOND_STATE_NONE);
+}
+
+static void mgmt_auth_failed_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_auth_failed *ev = param;
+
+       DBG("");
+
+       set_device_bond_state(&ev->addr.bdaddr, status_mgmt2hal(ev->status),
+                                                       HAL_BOND_STATE_NONE);
+}
+
+static void mgmt_device_unpaired_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       DBG("");
+}
+
+static void register_mgmt_handlers(void)
+{
+       mgmt_register(mgmt_if, MGMT_EV_NEW_SETTINGS, adapter.index,
+                                       new_settings_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_CLASS_OF_DEV_CHANGED, adapter.index,
+                               mgmt_dev_class_changed_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_LOCAL_NAME_CHANGED, adapter.index,
+                               mgmt_local_name_changed_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_NEW_LINK_KEY, adapter.index,
+                                       new_link_key_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_PIN_CODE_REQUEST, adapter.index,
+                                       pin_code_request_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_USER_CONFIRM_REQUEST, adapter.index,
+                               user_confirm_request_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_USER_PASSKEY_REQUEST, adapter.index,
+                               user_passkey_request_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_PASSKEY_NOTIFY, adapter.index,
+                               user_passkey_notify_callback, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_DISCOVERING, adapter.index,
+                                       mgmt_discovering_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_DEVICE_FOUND, adapter.index,
+                                       mgmt_device_found_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_DEVICE_CONNECTED, adapter.index,
+                               mgmt_device_connected_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_DEVICE_DISCONNECTED, adapter.index,
+                               mgmt_device_disconnected_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_CONNECT_FAILED, adapter.index,
+                                       mgmt_connect_failed_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_AUTH_FAILED, adapter.index,
+                                       mgmt_auth_failed_event, NULL, NULL);
+
+       mgmt_register(mgmt_if, MGMT_EV_DEVICE_UNPAIRED, adapter.index,
+                               mgmt_device_unpaired_event, NULL, NULL);
+}
+
+static void load_link_keys_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       bt_bluetooth_ready cb = user_data;
+       int err;
+
+       if (status) {
+               error("Failed to load link keys for index %u: %s (0x%02x)",
+                               adapter.index, mgmt_errstr(status), status);
+               err = -EIO;
+               goto failed;
+       }
+
+       DBG("status %u", status);
+
+       cb(0, &adapter.bdaddr);
+       return;
+
+failed:
+       cb(err, NULL);
+}
+
+static void load_link_keys(GSList *keys, bt_bluetooth_ready cb)
+{
+       struct mgmt_cp_load_link_keys *cp;
+       struct mgmt_link_key_info *key;
+       size_t key_count, cp_size;
+       unsigned int id;
+
+       key_count = g_slist_length(keys);
+
+       DBG("keys %zu ", key_count);
+
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+       cp = g_malloc0(cp_size);
+
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way it is ensured
+        * that no old keys from a previous daemon are present.
+        */
+       cp->key_count = htobs(key_count);
+
+       for (key = cp->keys; keys != NULL; keys = g_slist_next(keys), key++)
+               memcpy(key, keys->data, sizeof(*key));
+
+       id = mgmt_send(mgmt_if, MGMT_OP_LOAD_LINK_KEYS, adapter.index,
+                       cp_size, cp, load_link_keys_complete, cb, NULL);
+
+       g_free(cp);
+
+       if (id == 0) {
+               error("Failed to load link keys");
+               cb(-EIO, NULL);
+       }
+}
+
+/* output uint128 is in host order */
+static void uuid16_to_uint128(uint16_t uuid, uint128_t *u128)
+{
+       uuid_t uuid16, uuid128;
+
+       sdp_uuid16_create(&uuid16, uuid);
+       sdp_uuid16_to_uuid128(&uuid128, &uuid16);
+
+       ntoh128(&uuid128.value.uuid128, u128);
+}
+
+static bool get_uuids(void)
+{
+       struct hal_ev_adapter_props_changed *ev;
+       GSList *list = adapter.uuids;
+       unsigned int uuid_count = g_slist_length(list);
+       int len = uuid_count * sizeof(uint128_t);
+       uint8_t buf[BASELEN_PROP_CHANGED + len];
+       uint8_t *p;
+       int i;
+
+       memset(buf, 0, sizeof(buf));
+       ev = (void *) buf;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+
+       ev->props[0].type = HAL_PROP_ADAPTER_UUIDS;
+       ev->props[0].len = len;
+       p = ev->props->val;
+
+       for (; list; list = g_slist_next(list)) {
+               uint16_t uuid = GPOINTER_TO_UINT(list->data);
+               uint128_t uint128;
+
+               uuid16_to_uint128(uuid, &uint128);
+
+               /* Android expects swapped bytes in uuid */
+               for (i = 0; i < 16; i++)
+                       p[15 - i] = uint128.data[i];
+
+               p += sizeof(uint128_t);
+       }
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), ev, -1);
+
+       return true;
+}
+
+static void remove_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to remove UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       mgmt_dev_class_changed_event(adapter.index, length, param, NULL);
+
+       /* send notification only if bluetooth service is registered */
+       if (notification_sk >= 0)
+               get_uuids();
+}
+
+static void remove_uuid(uint16_t uuid)
+{
+       uint128_t uint128;
+       struct mgmt_cp_remove_uuid cp;
+
+       uuid16_to_uint128(uuid, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+
+       mgmt_send(mgmt_if, MGMT_OP_REMOVE_UUID, adapter.index, sizeof(cp), &cp,
+                                       remove_uuid_complete, NULL, NULL);
+}
+
+static void add_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to add UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       mgmt_dev_class_changed_event(adapter.index, length, param, NULL);
+
+       /* send notification only if bluetooth service is registered */
+       if (notification_sk >= 0)
+               get_uuids();
+}
+
+static void add_uuid(uint8_t svc_hint, uint16_t uuid)
+{
+       uint128_t uint128;
+       struct mgmt_cp_add_uuid cp;
+
+       uuid16_to_uint128(uuid, &uint128);
+
+       htob128(&uint128, (uint128_t *) cp.uuid);
+       cp.svc_hint = svc_hint;
+
+       mgmt_send(mgmt_if, MGMT_OP_ADD_UUID, adapter.index, sizeof(cp), &cp,
+                                               add_uuid_complete, NULL, NULL);
+}
+
+int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint)
+{
+       uint16_t uuid;
+
+       /* TODO support all types? */
+       if (rec->svclass.type != SDP_UUID16) {
+               warn("Ignoring unsupported UUID type");
+               return -EINVAL;
+       }
+
+       uuid = rec->svclass.value.uuid16;
+
+       if (g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid))) {
+               DBG("UUID 0x%x already added", uuid);
+               return -EALREADY;
+       }
+
+       adapter.uuids = g_slist_prepend(adapter.uuids, GUINT_TO_POINTER(uuid));
+
+       add_uuid(svc_hint, uuid);
+
+       return add_record_to_server(&adapter.bdaddr, rec);
+}
+
+void bt_adapter_remove_record(uint32_t handle)
+{
+       sdp_record_t *rec;
+       GSList *uuid_found;
+       uint16_t uuid;
+
+       rec = sdp_record_find(handle);
+       if (!rec)
+               return;
+
+       uuid = rec->svclass.value.uuid16;
+
+       uuid_found = g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid));
+       if (uuid_found) {
+               remove_uuid(uuid);
+
+               adapter.uuids = g_slist_remove(adapter.uuids,
+                                                       uuid_found->data);
+       }
+
+       remove_record_from_server(handle);
+}
+
+static void set_mode_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set mode: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       new_settings_callback(adapter.index, length, param, NULL);
+}
+
+static bool set_mode(uint16_t opcode, uint8_t mode)
+{
+       struct mgmt_mode cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
+
+       DBG("opcode=0x%x mode=0x%x", opcode, mode);
+
+       if (mgmt_send(mgmt_if, opcode, adapter.index, sizeof(cp), &cp,
+                                       set_mode_complete, NULL, NULL) > 0)
+               return true;
+
+       error("Failed to set mode");
+
+       return false;
+}
+
+static void set_io_capability(void)
+{
+       struct mgmt_cp_set_io_capability cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.io_capability = DEFAULT_IO_CAPABILITY;
+
+       if (mgmt_send(mgmt_if, MGMT_OP_SET_IO_CAPABILITY, adapter.index,
+                               sizeof(cp), &cp, NULL, NULL, NULL) == 0)
+               error("Failed to set IO capability");
+}
+
+static void set_device_id(void)
+{
+       struct mgmt_cp_set_device_id cp;
+       uint8_t major, minor;
+       uint16_t version;
+
+       if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
+               return;
+
+       version = major << 8 | minor;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.source = htobs(DEVICE_ID_SOURCE);
+       cp.vendor = htobs(DEVICE_ID_VENDOR);
+       cp.product = htobs(DEVICE_ID_PRODUCT);
+       cp.version = htobs(version);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_SET_DEVICE_ID, adapter.index,
+                               sizeof(cp), &cp, NULL, NULL, NULL) == 0)
+               error("Failed to set device id");
+
+       register_device_id(DEVICE_ID_SOURCE, DEVICE_ID_VENDOR,
+                                               DEVICE_ID_PRODUCT, version);
+
+       bt_adapter_add_record(sdp_record_find(0x10000), 0x00);
+}
+
+static void set_adapter_name_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_cp_set_local_name *rp = param;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set name: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       adapter_set_name(rp->name);
+}
+
+static uint8_t set_adapter_name(uint8_t *name, uint16_t len)
+{
+       struct mgmt_cp_set_local_name cp;
+
+       memset(&cp, 0, sizeof(cp));
+       memcpy(cp.name, name, len);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_SET_LOCAL_NAME, adapter.index,
+                               sizeof(cp), &cp, set_adapter_name_complete,
+                               NULL, NULL) > 0)
+               return HAL_STATUS_SUCCESS;
+
+       error("Failed to set name");
+
+       return HAL_STATUS_FAILED;
+}
+
+static uint8_t set_discoverable_timeout(uint8_t *timeout)
+{
+       /* Android handles discoverable timeout in Settings app.
+        * There is no need to use kernel feature for that.
+        * Just need to store this value here */
+
+       /* TODO: This should be in some storage */
+       memcpy(&adapter.discoverable_timeout, timeout, sizeof(uint32_t));
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static void clear_uuids(void)
+{
+       struct mgmt_cp_remove_uuid cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       mgmt_send(mgmt_if, MGMT_OP_REMOVE_UUID, adapter.index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void read_info_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_info *rp = param;
+       bt_bluetooth_ready cb = user_data;
+       uint32_t missing_settings, supported_settings;
+       int err;
+
+       DBG("");
+
+       if (status) {
+               error("Failed to read info for index %u: %s (0x%02x)",
+                               adapter.index, mgmt_errstr(status), status);
+               err = -EIO;
+               goto failed;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Too small read info complete response");
+               err = -EIO;
+               goto failed;
+       }
+
+       if (!bacmp(&rp->bdaddr, BDADDR_ANY)) {
+               error("No Bluetooth address");
+               err = -ENODEV;
+               goto failed;
+       }
+
+       /* Store adapter information */
+       bacpy(&adapter.bdaddr, &rp->bdaddr);
+       adapter.dev_class = rp->dev_class[0] | (rp->dev_class[1] << 8) |
+                                               (rp->dev_class[2] << 16);
+       adapter.name = g_strdup((const char *) rp->name);
+
+       supported_settings = btohs(rp->supported_settings);
+       adapter.current_settings = btohs(rp->current_settings);
+
+       /* TODO: Read discoverable timeout from storage here */
+
+       /* TODO: Register all event notification handlers */
+       register_mgmt_handlers();
+
+       clear_uuids();
+
+       load_link_keys(NULL, cb);
+
+       set_io_capability();
+       set_device_id();
+
+       missing_settings = adapter.current_settings ^ supported_settings;
+
+       if (missing_settings & MGMT_SETTING_SSP)
+               set_mode(MGMT_OP_SET_SSP, 0x01);
+
+       if (missing_settings & MGMT_SETTING_PAIRABLE)
+               set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
+
+       return;
+
+failed:
+       cb(err, NULL);
+}
+
+static void mgmt_index_added_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       bt_bluetooth_ready cb = user_data;
+
+       DBG("index %u", index);
+
+       if (adapter.index != MGMT_INDEX_NONE) {
+               DBG("skip event for index %u", index);
+               return;
+       }
+
+       if (option_index != MGMT_INDEX_NONE && option_index != index) {
+               DBG("skip event for index %u (option %u)", index, option_index);
+               return;
+       }
+
+       adapter.index = index;
+
+       if (mgmt_send(mgmt_if, MGMT_OP_READ_INFO, index, 0, NULL,
+                               read_info_complete, cb, NULL) == 0) {
+               cb(-EIO, NULL);
+               return;
+       }
+}
+
+static void mgmt_index_removed_event(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       DBG("index %u", index);
+
+       if (index != adapter.index)
+               return;
+
+       error("Adapter was removed. Exiting.");
+       raise(SIGTERM);
+}
+
+static void read_index_list_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_index_list *rp = param;
+       bt_bluetooth_ready cb = user_data;
+       uint16_t num;
+       int i;
+
+       DBG("");
+
+       if (status) {
+               error("%s: Failed to read index list: %s (0x%02x)",
+                                       __func__, mgmt_errstr(status), status);
+               goto failed;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("%s: Wrong size of read index list response", __func__);
+               goto failed;
+       }
+
+       num = btohs(rp->num_controllers);
+
+       DBG("Number of controllers: %u", num);
+
+       if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+               error("%s: Incorrect pkt size for index list rsp", __func__);
+               goto failed;
+       }
+
+       if (adapter.index != MGMT_INDEX_NONE)
+               return;
+
+       for (i = 0; i < num; i++) {
+               uint16_t index = btohs(rp->index[i]);
+
+               if (option_index != MGMT_INDEX_NONE && option_index != index)
+                       continue;
+
+               if (mgmt_send(mgmt_if, MGMT_OP_READ_INFO, index, 0, NULL,
+                                       read_info_complete, cb, NULL) == 0)
+                       goto failed;
+
+               adapter.index = index;
+               return;
+       }
+
+       return;
+
+failed:
+       cb(-EIO, NULL);
+}
+
+static void read_version_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_version *rp = param;
+       uint8_t mgmt_version, mgmt_revision;
+       bt_bluetooth_ready cb = user_data;
+
+       DBG("");
+
+       if (status) {
+               error("Failed to read version information: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               goto failed;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size response");
+               goto failed;
+       }
+
+       mgmt_version = rp->version;
+       mgmt_revision = btohs(rp->revision);
+
+       info("Bluetooth management interface %u.%u initialized",
+                                               mgmt_version, mgmt_revision);
+
+       if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 3)) {
+               error("Version 1.3 or later of management interface required");
+               goto failed;
+       }
+
+       mgmt_register(mgmt_if, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                       mgmt_index_added_event, cb, NULL);
+       mgmt_register(mgmt_if, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                       mgmt_index_removed_event, NULL, NULL);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0,
+                               NULL, read_index_list_complete, cb, NULL) > 0)
+               return;
+
+       error("Failed to read controller index list");
+
+failed:
+       cb(-EIO, NULL);
+}
+
+bool bt_bluetooth_start(int index, bt_bluetooth_ready cb)
+{
+       DBG("index %d", index);
+
+       mgmt_if = mgmt_new_default();
+       if (!mgmt_if) {
+               error("Failed to access management interface");
+               return false;
+       }
+
+       if (mgmt_send(mgmt_if, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
+                               read_version_complete, cb, NULL) == 0) {
+               error("Error sending READ_VERSION mgmt command");
+
+               mgmt_unref(mgmt_if);
+               mgmt_if = NULL;
+
+               return false;
+       }
+
+       if (index >= 0)
+               option_index = index;
+
+       return true;
+}
+
+static void shutdown_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       bt_bluetooth_stopped cb = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS)
+               error("Clean controller shutdown failed");
+
+       cb();
+}
+
+bool bt_bluetooth_stop(bt_bluetooth_stopped cb)
+{
+       struct mgmt_mode cp;
+
+       if (adapter.index == MGMT_INDEX_NONE)
+               return false;
+
+       info("Switching controller off");
+
+       memset(&cp, 0, sizeof(cp));
+
+       return mgmt_send(mgmt_if, MGMT_OP_SET_POWERED, adapter.index,
+                               sizeof(cp), &cp, shutdown_complete, (void *)cb,
+                               NULL) > 0;
+}
+
+void bt_bluetooth_cleanup(void)
+{
+       g_free(adapter.name);
+       adapter.name = NULL;
+
+       mgmt_unref(mgmt_if);
+       mgmt_if = NULL;
+}
+
+static bool set_discoverable(uint8_t mode, uint16_t timeout)
+{
+       struct mgmt_cp_set_discoverable cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
+       cp.timeout = htobs(timeout);
+
+       DBG("mode %u timeout %u", mode, timeout);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_SET_DISCOVERABLE, adapter.index,
+                       sizeof(cp), &cp, set_mode_complete, NULL, NULL) > 0)
+               return true;
+
+       error("Failed to set mode discoverable");
+
+       return false;
+}
+
+static void get_address(void)
+{
+       uint8_t buf[BASELEN_PROP_CHANGED + sizeof(bdaddr_t)];
+       struct hal_ev_adapter_props_changed *ev = (void *) buf;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+
+       ev->props[0].type = HAL_PROP_ADAPTER_ADDR;
+       ev->props[0].len = sizeof(bdaddr_t);
+       bdaddr2android(&adapter.bdaddr, ev->props[0].val);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), buf, -1);
+}
+
+static bool get_name(void)
+{
+       if (!adapter.name)
+               return false;
+
+       adapter_name_changed((uint8_t *) adapter.name);
+
+       return true;
+}
+
+
+static bool get_class(void)
+{
+       DBG("");
+
+       adapter_class_changed();
+
+       return true;
+}
+
+static bool get_type(void)
+{
+       DBG("Not implemented");
+
+       /* TODO: Add implementation */
+
+       return false;
+}
+
+static bool get_service(void)
+{
+       DBG("Not implemented");
+
+       /* TODO: Add implementation */
+
+       return false;
+}
+
+static bool get_scan_mode(void)
+{
+       DBG("");
+
+       scan_mode_changed();
+
+       return true;
+}
+
+static bool get_devices(void)
+{
+       DBG("Not implemented");
+
+       /* TODO: Add implementation */
+
+       return false;
+}
+
+static bool get_discoverable_timeout(void)
+{
+       struct hal_ev_adapter_props_changed *ev;
+       uint8_t buf[BASELEN_PROP_CHANGED + sizeof(uint32_t)];
+
+       memset(buf, 0, sizeof(buf));
+       ev = (void *) buf;
+
+       ev->num_props = 1;
+       ev->status = HAL_STATUS_SUCCESS;
+
+       ev->props[0].type = HAL_PROP_ADAPTER_DISC_TIMEOUT;
+       ev->props[0].len = sizeof(uint32_t);
+       memcpy(&ev->props[0].val, &adapter.discoverable_timeout,
+                                                       sizeof(uint32_t));
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_EV_ADAPTER_PROPS_CHANGED, sizeof(buf), ev, -1);
+
+       return true;
+}
+
+static bool get_property(void *buf, uint16_t len)
+{
+       struct hal_cmd_get_adapter_prop *cmd = buf;
+
+       switch (cmd->type) {
+       case HAL_PROP_ADAPTER_ADDR:
+               get_address();
+               return true;
+       case HAL_PROP_ADAPTER_NAME:
+               return get_name();
+       case HAL_PROP_ADAPTER_UUIDS:
+               return get_uuids();
+       case HAL_PROP_ADAPTER_CLASS:
+               return get_class();
+       case HAL_PROP_ADAPTER_TYPE:
+               return get_type();
+       case HAL_PROP_ADAPTER_SERVICE_REC:
+               return get_service();
+       case HAL_PROP_ADAPTER_SCAN_MODE:
+               return get_scan_mode();
+       case HAL_PROP_ADAPTER_BONDED_DEVICES:
+               return get_devices();
+       case HAL_PROP_ADAPTER_DISC_TIMEOUT:
+               return get_discoverable_timeout();
+       default:
+               return false;
+       }
+}
+
+static void get_properties(void)
+{
+       get_address();
+       get_name();
+       get_uuids();
+       get_class();
+       get_type();
+       get_service();
+       get_scan_mode();
+       get_devices();
+       get_discoverable_timeout();
+}
+
+static bool start_discovery(void)
+{
+       struct mgmt_cp_start_discovery cp;
+       uint8_t type = 1 << BDADDR_BREDR;
+
+       if (adapter.current_settings & type)
+               cp.type = type;
+       else
+               cp.type = 0;
+
+       DBG("type=0x%x", type);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_START_DISCOVERY, adapter.index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL) > 0)
+               return true;
+
+       error("Failed to start discovery");
+       return false;
+}
+
+static bool stop_discovery(void)
+{
+       struct mgmt_cp_stop_discovery cp;
+       uint8_t type = 1 << BDADDR_BREDR;
+
+       if (adapter.current_settings & type)
+               cp.type = type;
+       else
+               cp.type = 0;
+
+       DBG("type=0x%x", type);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_STOP_DISCOVERY, adapter.index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL) > 0)
+               return true;
+
+       error("Failed to start discovery");
+       return false;
+}
+
+static uint8_t set_scan_mode(void *buf, uint16_t len)
+{
+       uint8_t *mode = buf;
+       bool conn, disc, cur_conn, cur_disc;
+
+       cur_conn = adapter.current_settings & MGMT_SETTING_CONNECTABLE;
+       cur_disc = adapter.current_settings & MGMT_SETTING_DISCOVERABLE;
+
+       DBG("connectable %u discoverable %d mode %u", cur_conn, cur_disc,
+                                                               *mode);
+
+       switch (*mode) {
+       case HAL_ADAPTER_SCAN_MODE_NONE:
+               if (!cur_conn && !cur_disc)
+                       goto done;
+
+               conn = false;
+               disc = false;
+               break;
+       case HAL_ADAPTER_SCAN_MODE_CONN:
+               if (cur_conn && !cur_disc)
+                       goto done;
+
+               conn = true;
+               disc = false;
+               break;
+       case HAL_ADAPTER_SCAN_MODE_CONN_DISC:
+               if (cur_conn && cur_disc)
+                       goto done;
+
+               conn = true;
+               disc = true;
+               break;
+       default:
+               return HAL_STATUS_FAILED;
+       }
+
+       if (cur_conn != conn) {
+               if (!set_mode(MGMT_OP_SET_CONNECTABLE, conn ? 0x01 : 0x00))
+                       return HAL_STATUS_FAILED;
+       }
+
+       if (cur_disc != disc) {
+               if (!set_discoverable(disc ? 0x01 : 0x00, 0))
+                       return HAL_STATUS_FAILED;
+       }
+
+       return HAL_STATUS_SUCCESS;
+
+done:
+       /* Android expects property changed callback */
+       scan_mode_changed();
+
+       return HAL_STATUS_DONE;
+}
+
+static uint8_t set_property(void *buf, uint16_t len)
+{
+       struct hal_cmd_set_adapter_prop *cmd = buf;
+
+       switch (cmd->type) {
+       case HAL_PROP_ADAPTER_SCAN_MODE:
+               return set_scan_mode(cmd->val, cmd->len);
+       case HAL_PROP_ADAPTER_NAME:
+               return set_adapter_name(cmd->val, cmd->len);
+       case HAL_PROP_ADAPTER_DISC_TIMEOUT:
+               return set_discoverable_timeout(cmd->val);
+       default:
+               DBG("Unhandled property type 0x%x", cmd->type);
+               return HAL_STATUS_FAILED;
+       }
+}
+
+static void pair_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_pair_device *rp = param;
+
+       DBG("status %u", status);
+
+       /* On success bond state change will be send when new link key event
+        * is received */
+       if (status == MGMT_STATUS_SUCCESS)
+               return;
+
+       set_device_bond_state(&rp->addr.bdaddr, status_mgmt2hal(status),
+                                                       HAL_BOND_STATE_NONE);
+}
+
+static bool create_bond(void *buf, uint16_t len)
+{
+       struct hal_cmd_create_bond *cmd = buf;
+       struct mgmt_cp_pair_device cp;
+
+       cp.io_cap = DEFAULT_IO_CAPABILITY;
+       cp.addr.type = BDADDR_BREDR;
+       android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
+
+       if (mgmt_send(mgmt_if, MGMT_OP_PAIR_DEVICE, adapter.index, sizeof(cp),
+                               &cp, pair_device_complete, NULL, NULL) == 0)
+               return false;
+
+       set_device_bond_state(&cp.addr.bdaddr, HAL_STATUS_SUCCESS,
+                                               HAL_BOND_STATE_BONDING);
+
+       return true;
+}
+
+static bool cancel_bond(void *buf, uint16_t len)
+{
+       struct hal_cmd_cancel_bond *cmd = buf;
+       struct mgmt_addr_info cp;
+
+       cp.type = BDADDR_BREDR;
+       android2bdaddr(cmd->bdaddr, &cp.bdaddr);
+
+       return mgmt_reply(mgmt_if, MGMT_OP_CANCEL_PAIR_DEVICE, adapter.index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL) > 0;
+}
+
+static void unpair_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_unpair_device *rp = param;
+
+       DBG("status %u", status);
+
+       if (status != MGMT_STATUS_SUCCESS)
+               return;
+
+       set_device_bond_state(&rp->addr.bdaddr, HAL_STATUS_SUCCESS,
+                                                       HAL_BOND_STATE_NONE);
+}
+
+static bool remove_bond(void *buf, uint16_t len)
+{
+       struct hal_cmd_remove_bond *cmd = buf;
+       struct mgmt_cp_unpair_device cp;
+
+       cp.disconnect = 1;
+       cp.addr.type = BDADDR_BREDR;
+       android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
+
+       return mgmt_send(mgmt_if, MGMT_OP_UNPAIR_DEVICE, adapter.index,
+                               sizeof(cp), &cp, unpair_device_complete,
+                               NULL, NULL) > 0;
+}
+
+static uint8_t pin_reply(void *buf, uint16_t len)
+{
+       struct hal_cmd_pin_reply *cmd = buf;
+       bdaddr_t bdaddr;
+       char addr[18];
+
+       android2bdaddr(cmd->bdaddr, &bdaddr);
+       ba2str(&bdaddr, addr);
+
+       DBG("%s accept %u pin_len %u", addr, cmd->accept, cmd->pin_len);
+
+       if (!cmd->accept && cmd->pin_len)
+               return HAL_STATUS_INVALID;
+
+       if (cmd->accept) {
+               struct mgmt_cp_pin_code_reply rp;
+
+               memset(&rp, 0, sizeof(rp));
+
+               bacpy(&rp.addr.bdaddr, &bdaddr);
+               rp.addr.type = BDADDR_BREDR;
+               rp.pin_len = cmd->pin_len;
+               memcpy(rp.pin_code, cmd->pin_code, rp.pin_len);
+
+               if (mgmt_reply(mgmt_if, MGMT_OP_PIN_CODE_REPLY, adapter.index,
+                               sizeof(rp), &rp, NULL, NULL, NULL) == 0)
+                       return HAL_STATUS_FAILED;
+       } else {
+               struct mgmt_cp_pin_code_neg_reply rp;
+
+               bacpy(&rp.addr.bdaddr, &bdaddr);
+               rp.addr.type = BDADDR_BREDR;
+
+               if (mgmt_reply(mgmt_if, MGMT_OP_PIN_CODE_NEG_REPLY,
+                                               adapter.index, sizeof(rp), &rp,
+                                               NULL, NULL, NULL) == 0)
+                       return HAL_STATUS_FAILED;
+       }
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t user_confirm_reply(const bdaddr_t *bdaddr, bool accept)
+{
+       struct mgmt_addr_info cp;
+       uint16_t opcode;
+
+       if (accept)
+               opcode = MGMT_OP_USER_CONFIRM_REPLY;
+       else
+               opcode = MGMT_OP_USER_CONFIRM_NEG_REPLY;
+
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.type = BDADDR_BREDR;
+
+       if (mgmt_reply(mgmt_if, opcode, adapter.index, sizeof(cp), &cp,
+                                                       NULL, NULL, NULL) > 0)
+               return HAL_STATUS_SUCCESS;
+
+       return HAL_STATUS_FAILED;
+}
+
+static uint8_t user_passkey_reply(const bdaddr_t *bdaddr, bool accept,
+                                                       uint32_t passkey)
+{
+       unsigned int id;
+
+       if (accept) {
+               struct mgmt_cp_user_passkey_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+               cp.passkey = htobl(passkey);
+
+               id = mgmt_reply(mgmt_if, MGMT_OP_USER_PASSKEY_REPLY,
+                                               adapter.index, sizeof(cp), &cp,
+                                               NULL, NULL, NULL);
+       } else {
+               struct mgmt_cp_user_passkey_neg_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+
+               id = mgmt_reply(mgmt_if, MGMT_OP_USER_PASSKEY_NEG_REPLY,
+                                               adapter.index, sizeof(cp), &cp,
+                                               NULL, NULL, NULL);
+       }
+
+       if (id == 0)
+               return HAL_STATUS_FAILED;
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t ssp_reply(void *buf, uint16_t len)
+{
+       struct hal_cmd_ssp_reply *cmd = buf;
+       uint8_t status;
+       bdaddr_t bdaddr;
+       char addr[18];
+
+       /* TODO should parameters sanity be verified here? */
+
+       android2bdaddr(cmd->bdaddr, &bdaddr);
+       ba2str(&bdaddr, addr);
+
+       DBG("%s variant %u accept %u", addr, cmd->ssp_variant, cmd->accept);
+
+       switch (cmd->ssp_variant) {
+       case HAL_SSP_VARIANT_CONFIRM:
+       case HAL_SSP_VARIANT_CONSENT:
+               status = user_confirm_reply(&bdaddr, cmd->accept);
+               break;
+       case HAL_SSP_VARIANT_ENTRY:
+               status = user_passkey_reply(&bdaddr, cmd->accept,
+                                                               cmd->passkey);
+               break;
+       case HAL_SSP_VARIANT_NOTIF:
+               status = HAL_STATUS_SUCCESS;
+               break;
+       default:
+               status = HAL_STATUS_INVALID;
+               break;
+       }
+
+       return status;
+}
+
+static uint8_t get_remote_services(void *buf, uint16_t len)
+{
+       struct hal_cmd_get_remote_services *cmd = buf;
+       bdaddr_t addr;
+
+       android2bdaddr(&cmd->bdaddr, &addr);
+
+       return browse_remote_sdp(&addr);
+}
+
+void bt_bluetooth_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
+{
+       uint8_t status = HAL_STATUS_FAILED;
+
+       switch (opcode) {
+       case HAL_OP_ENABLE:
+               /* Framework expects all properties to be emitted while
+                * enabling adapter */
+               get_properties();
+
+               if (adapter.current_settings & MGMT_SETTING_POWERED) {
+                       status = HAL_STATUS_DONE;
+                       goto error;
+               }
+
+               if (!set_mode(MGMT_OP_SET_POWERED, 0x01))
+                       goto error;
+
+               break;
+       case HAL_OP_DISABLE:
+               if (!(adapter.current_settings & MGMT_SETTING_POWERED)) {
+                       status = HAL_STATUS_DONE;
+                       goto error;
+               }
+
+               if (!set_mode(MGMT_OP_SET_POWERED, 0x00))
+                       goto error;
+
+               break;
+       case HAL_OP_GET_ADAPTER_PROPS:
+               get_properties();
+
+               break;
+       case HAL_OP_GET_ADAPTER_PROP:
+               if (!get_property(buf, len))
+                       goto error;
+
+               break;
+       case HAL_OP_SET_ADAPTER_PROP:
+               status = set_property(buf, len);
+               if (status != HAL_STATUS_SUCCESS && status != HAL_STATUS_DONE)
+                       goto error;
+
+               break;
+       case HAL_OP_CREATE_BOND:
+               if (!create_bond(buf, len))
+                       goto error;
+
+               break;
+       case HAL_OP_CANCEL_BOND:
+               if (!cancel_bond(buf, len))
+                       goto error;
+
+               break;
+       case HAL_OP_REMOVE_BOND:
+               if (!remove_bond(buf, len))
+                       goto error;
+
+               break;
+       case HAL_OP_PIN_REPLY:
+               status = pin_reply(buf, len);
+               if (status != HAL_STATUS_SUCCESS)
+                       goto error;
+
+               break;
+       case HAL_OP_SSP_REPLY:
+               status = ssp_reply(buf, len);
+               if (status != HAL_STATUS_SUCCESS)
+                       goto error;
+               break;
+       case HAL_OP_START_DISCOVERY:
+               if (adapter.discovering) {
+                       status = HAL_STATUS_DONE;
+                       goto error;
+               }
+
+               if (!(adapter.current_settings & MGMT_SETTING_POWERED)) {
+                       status = HAL_STATUS_NOT_READY;
+                       goto error;
+               }
+
+               if (!start_discovery())
+                       goto error;
+
+               break;
+       case HAL_OP_CANCEL_DISCOVERY:
+               if (!adapter.discovering) {
+                       status = HAL_STATUS_DONE;
+                       goto error;
+               }
+
+               if (!(adapter.current_settings & MGMT_SETTING_POWERED)) {
+                       status = HAL_STATUS_NOT_READY;
+                       goto error;
+               }
+
+               if (!stop_discovery())
+                       goto error;
+
+               break;
+       case HAL_OP_GET_REMOTE_SERVICES:
+               status = get_remote_services(buf, len);
+               if (status != HAL_STATUS_SUCCESS)
+                       goto error;
+               break;
+       default:
+               DBG("Unhandled command, opcode 0x%x", opcode);
+               goto error;
+       }
+
+       ipc_send(sk, HAL_SERVICE_ID_BLUETOOTH, opcode, 0, NULL, -1);
+       return;
+
+error:
+       error("Error handling command 0x%02x status %u", opcode, status);
+
+       ipc_send_rsp(sk, HAL_SERVICE_ID_BLUETOOTH, status);
+}
+
+bool bt_bluetooth_register(int sk)
+{
+       DBG("");
+
+       notification_sk = sk;
+
+       return true;
+}
+
+void bt_bluetooth_unregister(void)
+{
+       DBG("");
+
+       notification_sk = -1;
+}
diff --git a/android/bluetooth.h b/android/bluetooth.h
new file mode 100644 (file)
index 0000000..44b8e9e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef void (*bt_bluetooth_ready)(int err, const bdaddr_t *addr);
+bool bt_bluetooth_start(int index, bt_bluetooth_ready cb);
+
+typedef void (*bt_bluetooth_stopped)(void);
+bool bt_bluetooth_stop(bt_bluetooth_stopped cb);
+
+void bt_bluetooth_cleanup(void);
+
+void bt_bluetooth_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
+
+bool bt_bluetooth_register(int sk);
+void bt_bluetooth_unregister(void);
+
+int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint);
+void bt_adapter_remove_record(uint32_t handle);
diff --git a/android/client/haltest.c b/android/client/haltest.c
new file mode 100644 (file)
index 0000000..7154d27
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <poll.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "if-main.h"
+#include "terminal.h"
+#include "pollhandler.h"
+#include "history.h"
+
+const struct interface *interfaces[] = {
+       &bluetooth_if,
+       &av_if,
+#if PLATFORM_SDK_VERSION > 17
+       &gatt_if,
+       &gatt_client_if,
+       &gatt_server_if,
+#endif
+       &hf_if,
+       &hh_if,
+       &pan_if,
+       &sock_if,
+       NULL
+};
+
+static struct method commands[];
+
+struct method *get_method(struct method *methods, const char *name)
+{
+       while (strcmp(methods->name, "") != 0) {
+               if (strcmp(methods->name, name) == 0)
+                       return methods;
+               methods++;
+       }
+
+       return NULL;
+}
+
+/* function returns interface of given name or NULL if not found */
+const struct interface *get_interface(const char *name)
+{
+       int i;
+
+       for (i = 0; interfaces[i] != NULL; ++i) {
+               if (strcmp(interfaces[i]->name, name) == 0)
+                       break;
+       }
+
+       return interfaces[i];
+}
+
+int haltest_error(const char *format, ...)
+{
+       va_list args;
+       int ret;
+       va_start(args, format);
+       ret = terminal_vprint(format, args);
+       va_end(args);
+       return ret;
+}
+
+int haltest_info(const char *format, ...)
+{
+       va_list args;
+       int ret;
+       va_start(args, format);
+       ret = terminal_vprint(format, args);
+       va_end(args);
+       return ret;
+}
+
+int haltest_warn(const char *format, ...)
+{
+       va_list args;
+       int ret;
+       va_start(args, format);
+       ret = terminal_vprint(format, args);
+       va_end(args);
+       return ret;
+}
+
+static void help_print_interface(const struct interface *i)
+{
+       struct method *m;
+
+       for (m = i->methods; strcmp(m->name, "") != 0; m++)
+               haltest_info("%s %s %s\n", i->name, m->name,
+                                               (m->help ? m->help : ""));
+}
+
+/* Help completion */
+static void help_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 2)
+               *enum_func = interface_name;
+}
+
+/* Help execution */
+static void help_p(int argc, const char **argv)
+{
+       const struct method *m = commands;
+       const struct interface **ip = interfaces;
+       const struct interface *i;
+
+       if (argc == 1) {
+               terminal_print("haltest allows to call Android HAL methods.\n");
+               terminal_print("\nAvailable commands:\n");
+               while (0 != strcmp(m->name, "")) {
+                       terminal_print("\t%s %s\n", m->name,
+                                               (m->help ? m->help : ""));
+                       m++;
+               }
+
+               terminal_print("\nAvailable interfaces to use:\n");
+               while (NULL != *ip) {
+                       terminal_print("\t%s\n", (*ip)->name);
+                       ip++;
+               }
+
+               terminal_print("\nTo get help on methods for each interface type:\n");
+               terminal_print("\n\thelp <inerface>\n");
+               terminal_print("\nBasic scenario:\n\tbluetooth init\n");
+               terminal_print("\tbluetooth enable\n\tbluetooth start_discovery\n");
+               terminal_print("\tbluetooth get_profile_interface handsfree\n");
+               terminal_print("\thandsfree init\n\n");
+               return;
+       }
+
+       i = get_interface(argv[1]);
+       if (i == NULL) {
+               haltest_error("No such interface\n");
+               return;
+       }
+
+       help_print_interface(i);
+}
+
+/* quit/exit execution */
+static void quit_p(int argc, const char **argv)
+{
+       exit(0);
+}
+
+static int fd_stack[10];
+static int fd_stack_pointer = 0;
+
+static void stdin_handler(struct pollfd *pollfd);
+
+static void process_file(const char *name)
+{
+       int fd = open(name, O_RDONLY);
+
+       if (fd < 0) {
+               haltest_error("Can't open file: %s for reading\n", name);
+               return;
+       }
+
+       if (fd_stack_pointer >= 10) {
+               haltest_error("To many open files\n");
+               close(fd);
+               return;
+       }
+
+       fd_stack[fd_stack_pointer++] = fd;
+       poll_unregister_fd(fd_stack[fd_stack_pointer - 2], stdin_handler);
+       poll_register_fd(fd_stack[fd_stack_pointer - 1], POLLIN, stdin_handler);
+}
+
+static void source_p(int argc, const char **argv)
+{
+       if (argc < 2) {
+               haltest_error("No file specified");
+               return;
+       }
+
+       process_file(argv[1]);
+}
+
+/* Commands available without interface */
+static struct method commands[] = {
+       STD_METHODCH(help, "[<interface>]"),
+       STD_METHOD(quit),
+       METHOD("exit", quit_p, NULL, NULL),
+       STD_METHODH(source, "<file>"),
+       END_METHOD
+};
+
+/* Gets comman by name */
+struct method *get_command(const char *name)
+{
+       return get_method(commands, name);
+}
+
+/* Function to enumerate interface names */
+const char *interface_name(void *v, int i)
+{
+       return interfaces[i] ? interfaces[i]->name : NULL;
+}
+
+/* Function to enumerate command and interface names */
+const char *command_name(void *v, int i)
+{
+       int cmd_cnt = NELEM(commands);
+
+       if (i >= cmd_cnt)
+               return interface_name(v, i - cmd_cnt);
+       else
+               return commands[i].name;
+}
+
+/*
+ * This function changes input parameter line_buffer so it has
+ * null termination after each token (due to strtok)
+ * Output argv is filled with pointers to arguments
+ * returns number of tokens parsed - argc
+ */
+static int command_line_to_argv(char *line_buffer, char *argv[], int argv_size)
+{
+       static const char *token_breaks = "\r\n\t ";
+       char *token;
+       int argc = 0;
+
+       token = strtok(line_buffer, token_breaks);
+       while (token != NULL && argc < (int) argv_size) {
+               argv[argc++] = token;
+               token = strtok(NULL, token_breaks);
+       }
+
+       return argc;
+}
+
+static void process_line(char *line_buffer)
+{
+       char *argv[10];
+       int argc;
+       int i = 0;
+       struct method *m;
+
+       argc = command_line_to_argv(line_buffer, argv, 10);
+       if (argc < 1)
+               return;
+
+       while (interfaces[i] != NULL) {
+               if (strcmp(interfaces[i]->name, argv[0])) {
+                       i++;
+                       continue;
+               }
+
+               if (argc < 2 || strcmp(argv[1], "?") == 0) {
+                       help_print_interface(interfaces[i]);
+                       return;
+               }
+
+               m = get_method(interfaces[i]->methods, argv[1]);
+               if (m != NULL) {
+                       m->func(argc, (const char **) argv);
+                       return;
+               }
+
+               haltest_error("No function %s found\n", argv[1]);
+               return;
+       }
+       /* No interface, try commands */
+       m = get_command(argv[0]);
+       if (m == NULL)
+               haltest_error("No such command %s\n", argv[0]);
+       else
+               m->func(argc, (const char **) argv);
+}
+
+/* called when there is something on stdin */
+static void stdin_handler(struct pollfd *pollfd)
+{
+       char buf[10];
+
+       if (pollfd->revents & POLLIN) {
+               int count = read(fd_stack[fd_stack_pointer - 1], buf, 10);
+
+               if (count > 0) {
+                       int i;
+
+                       for (i = 0; i < count; ++i)
+                               terminal_process_char(buf[i], process_line);
+                       return;
+               }
+       }
+
+       if (fd_stack_pointer > 1)
+               poll_register_fd(fd_stack[fd_stack_pointer - 2], POLLIN,
+                                                               stdin_handler);
+       if (fd_stack_pointer > 0) {
+               poll_unregister_fd(fd_stack[--fd_stack_pointer], stdin_handler);
+
+               if (fd_stack[fd_stack_pointer])
+                       close(fd_stack[fd_stack_pointer]);
+       }
+}
+
+static void usage(void)
+{
+       printf("haltest Android Bluetooth HAL testing tool\n"
+               "Usage:\n");
+       printf("\thaltest [options]\n");
+       printf("options:\n"
+               "\t-n, --no-init          Don't call init for interfaces\n"
+               "\t    --version          Print version\n"
+               "\t-h, --help             Show help options\n");
+}
+
+enum {
+       PRINT_VERSION = 1000
+};
+
+int version = 1;
+int revision = 0;
+
+static void print_version(void)
+{
+       printf("haltest version %d.%d\n", version, revision);
+}
+
+static const struct option main_options[] = {
+       { "no-init", no_argument, NULL, 'n' },
+       { "help",    no_argument, NULL, 'h' },
+       { "version", no_argument, NULL, PRINT_VERSION },
+       { NULL }
+};
+
+static bool no_init = false;
+
+static void parse_command_line(int argc, char *argv[])
+{
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "nh", main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'n':
+                       no_init = true;
+                       break;
+               case 'h':
+                       usage();
+                       exit(0);
+               case PRINT_VERSION:
+                       print_version();
+                       exit(0);
+               default:
+                       putchar('\n');
+                       exit(-1);
+                       break;
+               }
+       }
+}
+
+static void init(void)
+{
+       static const char * const inames[] = {
+               BT_PROFILE_HANDSFREE_ID,
+               BT_PROFILE_ADVANCED_AUDIO_ID,
+               BT_PROFILE_HEALTH_ID,
+               BT_PROFILE_HIDHOST_ID,
+               BT_PROFILE_PAN_ID,
+#if PLATFORM_SDK_VERSION > 17
+               BT_PROFILE_GATT_ID,
+#endif
+               BT_PROFILE_SOCKETS_ID
+       };
+       const struct method *m;
+       const char *argv[4];
+       char init_line[] = "bluetooth init";
+       uint32_t i;
+
+       process_line(init_line);
+       m = get_interface_method("bluetooth", "get_profile_interface");
+
+       for (i = 0; i < NELEM(inames); ++i) {
+               argv[2] = inames[i];
+               m->func(3, argv);
+       }
+
+       /* Init what is available to init */
+       for (i = 1; i < NELEM(interfaces) - 1; ++i) {
+               m = get_interface_method(interfaces[i]->name, "init");
+               if (m != NULL)
+                       m->func(2, argv);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       struct stat rcstat;
+
+       parse_command_line(argc, argv);
+
+       terminal_setup();
+
+       if (!no_init)
+               init();
+
+       history_restore(".haltest_history");
+
+       fd_stack[fd_stack_pointer++] = 0;
+       /* Register command line handler */
+       poll_register_fd(0, POLLIN, stdin_handler);
+
+       if (stat(".haltestrc", &rcstat) == 0 && (rcstat.st_mode & S_IFREG) != 0)
+               process_file(".haltestrc");
+
+       poll_dispatch_loop();
+
+       return 0;
+}
diff --git a/android/client/history.c b/android/client/history.c
new file mode 100644 (file)
index 0000000..ee285da
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "history.h"
+
+/*
+ * Very simple history storage for easy usage of tool
+ */
+
+#define HISTORY_DEPTH 20
+#define LINE_SIZE 100
+static char lines[HISTORY_DEPTH][LINE_SIZE];
+static int last_line = 0;
+static int history_size = 0;
+
+/* TODO: Storing history not implemented yet */
+void history_store(const char *filename)
+{
+}
+
+/* Restoring history from file */
+void history_restore(const char *filename)
+{
+       char line[1000];
+       FILE *f = fopen(filename, "rt");
+
+       if (f == NULL)
+               return;
+
+       for (;;) {
+               if (fgets(line, 1000, f) != NULL) {
+                       int l = strlen(line);
+
+                       while (l > 0 && isspace(line[--l]))
+                               line[l] = 0;
+
+                       if (l > 0)
+                               history_add_line(line);
+               } else
+                       break;
+       }
+
+       fclose(f);
+}
+
+/* Add new line to history buffer */
+void history_add_line(const char *line)
+{
+       if (line == NULL || strlen(line) == 0)
+               return;
+
+       if (strcmp(line, lines[last_line]) == 0)
+               return;
+
+       last_line = (last_line + 1) % HISTORY_DEPTH;
+       strncpy(&lines[last_line][0], line, LINE_SIZE - 1);
+       if (history_size < HISTORY_DEPTH)
+               history_size++;
+}
+
+/*
+ * Get n-th line from history
+ * 0 - means latest
+ * -1 - means oldest
+ * return -1 if there is no such line
+ */
+int history_get_line(int n, char *buf, int buf_size)
+{
+       if (n == -1)
+               n = history_size - 1;
+
+       if (n >= history_size || buf_size == 0 || n < 0)
+               return -1;
+
+       strncpy(buf,
+               &lines[(HISTORY_DEPTH + last_line - n) % HISTORY_DEPTH][0],
+               buf_size - 1);
+       buf[buf_size - 1] = 0;
+
+       return n;
+}
diff --git a/android/client/history.h b/android/client/history.h
new file mode 100644 (file)
index 0000000..26085b5
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 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.
+ *
+ */
+
+void history_store(const char *filename);
+void history_restore(const char *filename);
+void history_add_line(const char *line);
+int history_get_line(int n, char *buf, int buf_size);
diff --git a/android/client/hwmodule.c b/android/client/hwmodule.c
new file mode 100644 (file)
index 0000000..80e7475
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 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 "hardware/hardware.h"
+
+int hw_get_module(const char *id, const struct hw_module_t **module)
+{
+       extern struct hw_module_t HAL_MODULE_INFO_SYM;
+
+       *module = &HAL_MODULE_INFO_SYM;
+
+       return 0;
+}
diff --git a/android/client/if-av.c b/android/client/if-av.c
new file mode 100644 (file)
index 0000000..0470e0d
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 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 "if-main.h"
+#include "../hal-utils.h"
+
+const btav_interface_t *if_av = NULL;
+
+SINTMAP(btav_connection_state_t, -1, "(unknown)")
+       DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTED),
+       DELEMENT(BTAV_CONNECTION_STATE_CONNECTING),
+       DELEMENT(BTAV_CONNECTION_STATE_CONNECTED),
+       DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTING),
+ENDMAP
+
+SINTMAP(btav_audio_state_t, -1, "(unknown)")
+       DELEMENT(BTAV_AUDIO_STATE_REMOTE_SUSPEND),
+       DELEMENT(BTAV_AUDIO_STATE_STOPPED),
+       DELEMENT(BTAV_AUDIO_STATE_STARTED),
+ENDMAP
+
+static char last_addr[MAX_ADDR_STR_LEN];
+
+static void connection_state(btav_connection_state_t state,
+                                                       bt_bdaddr_t *bd_addr)
+{
+       haltest_info("%s: connection_state=%s remote_bd_addr=%s\n", __func__,
+                                       btav_connection_state_t2str(state),
+                                       bt_bdaddr_t2str(bd_addr, last_addr));
+}
+
+static void audio_state(btav_audio_state_t state, bt_bdaddr_t *bd_addr)
+{
+       haltest_info("%s: audio_state=%s remote_bd_addr=%s\n", __func__,
+                                       btav_audio_state_t2str(state),
+                                       bt_bdaddr_t2str(bd_addr, last_addr));
+}
+
+static btav_callbacks_t av_cbacks = {
+       .size = sizeof(av_cbacks),
+       .connection_state_cb = connection_state,
+       .audio_state_cb = audio_state
+};
+
+/* init */
+
+static void init_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_av);
+
+       EXEC(if_av->init, &av_cbacks);
+}
+
+/* connect */
+
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_av->connect, &addr);
+}
+
+/* disconnect */
+
+static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = last_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void disconnect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_av->disconnect, &addr);
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_av);
+
+       EXECV(if_av->cleanup);
+       if_av = NULL;
+}
+
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHODCH(connect, "<addr>"),
+       STD_METHODCH(disconnect, "<addr>"),
+       STD_METHOD(cleanup),
+       END_METHOD
+};
+
+const struct interface av_if = {
+       .name = "av",
+       .methods = methods
+};
diff --git a/android/client/if-bt.c b/android/client/if-bt.c
new file mode 100644 (file)
index 0000000..0cd43db
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2013 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 "if-main.h"
+#include "terminal.h"
+#include "../hal-utils.h"
+
+const bt_interface_t *if_bluetooth;
+
+#define VERIFY_PROP_TYPE_ARG(n, typ) \
+       do { \
+               if (n < argc) \
+                       typ = str2btpropertytype(argv[n]); \
+               else { \
+                       haltest_error("No property type specified\n"); \
+                       return;\
+               } \
+       } while (0)
+
+static bt_scan_mode_t str2btscanmode(const char *str)
+{
+       bt_scan_mode_t v = str2bt_scan_mode_t(str);
+
+       if ((int) v != -1)
+               return v;
+
+       haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+       return (bt_scan_mode_t) atoi(str);
+}
+
+static bt_ssp_variant_t str2btsspvariant(const char *str)
+{
+       bt_ssp_variant_t v = str2bt_ssp_variant_t(str);
+
+       if ((int) v != -1)
+               return v;
+
+       haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+       return (bt_ssp_variant_t) atoi(str);
+}
+
+static bt_property_type_t str2btpropertytype(const char *str)
+{
+       bt_property_type_t v = str2bt_property_type_t(str);
+
+       if ((int) v != -1)
+               return v;
+
+       haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+       return (bt_property_type_t) atoi(str);
+}
+
+static void dump_properties(int num_properties, bt_property_t *properties)
+{
+       int i;
+
+       for (i = 0; i < num_properties; i++) {
+               /*
+                * properities sometimes come unaligned hence memcp to
+                * aligned buffer
+                */
+               bt_property_t prop;
+               memcpy(&prop, properties + i, sizeof(prop));
+
+               haltest_info("prop: %s\n", btproperty2str(&prop));
+       }
+}
+
+/*
+ * Cache for remote devices, stored in sorted array
+ */
+static bt_bdaddr_t *remote_devices = NULL;
+static int remote_devices_cnt = 0;
+static int remote_devices_capacity = 0;
+
+/* Adds address to remote device set so it can be used in tab completion */
+void add_remote_device(const bt_bdaddr_t *addr)
+{
+       int i;
+
+       if (remote_devices == NULL) {
+               remote_devices = malloc(4 * sizeof(bt_bdaddr_t));
+               remote_devices_cnt = 0;
+               if (remote_devices == NULL) {
+                       remote_devices_capacity = 0;
+                       return;
+               }
+
+               remote_devices_capacity = 4;
+       }
+
+       /* Array is sorted, search for right place */
+       for (i = 0; i < remote_devices_cnt; ++i) {
+               int res = memcmp(&remote_devices[i], addr, sizeof(*addr));
+
+               if (res == 0)
+                       return; /* Already added */
+               else if (res > 0)
+                       break;
+       }
+
+       /* Realloc space if needed */
+       if (remote_devices_cnt >= remote_devices_capacity) {
+               remote_devices_capacity *= 2;
+               remote_devices = realloc(remote_devices, sizeof(bt_bdaddr_t) *
+                                               remote_devices_capacity);
+               if (remote_devices == NULL) {
+                       remote_devices_capacity = 0;
+                       remote_devices_cnt = 0;
+                       return;
+               }
+       }
+
+       if (i < remote_devices_cnt)
+               memmove(remote_devices + i + 1, remote_devices + i,
+                               (remote_devices_cnt - i) * sizeof(bt_bdaddr_t));
+       remote_devices[i] = *addr;
+       remote_devices_cnt++;
+}
+
+const char *enum_devices(void *v, int i)
+{
+       static char buf[MAX_ADDR_STR_LEN];
+
+       if (i >= remote_devices_cnt)
+               return NULL;
+
+       bt_bdaddr_t2str(&remote_devices[i], buf);
+       return buf;
+}
+
+static void add_remote_device_from_props(int num_properties,
+                                               const bt_property_t *properties)
+{
+       int i;
+
+       for (i = 0; i < num_properties; i++) {
+               /*
+                * properities sometimes come unaligned hence memcp to
+                * aligned buffer
+                */
+               bt_property_t property;
+
+               memcpy(&property, properties + i, sizeof(property));
+               if (property.type == BT_PROPERTY_BDADDR)
+                       add_remote_device((bt_bdaddr_t *) property.val);
+       }
+}
+
+static void adapter_state_changed_cb(bt_state_t state)
+{
+       haltest_info("%s: state=%s\n", __func__, bt_state_t2str(state));
+}
+
+static void adapter_properties_cb(bt_status_t status, int num_properties,
+                                               bt_property_t *properties)
+{
+       haltest_info("%s: status=%s num_properties=%d\n", __func__,
+                               bt_status_t2str(status), num_properties);
+
+       dump_properties(num_properties, properties);
+}
+
+static void remote_device_properties_cb(bt_status_t status,
+                                       bt_bdaddr_t *bd_addr,
+                                       int num_properties,
+                                       bt_property_t *properties)
+{
+       haltest_info("%s: status=%s bd_addr=%s num_properties=%d\n", __func__,
+                       bt_status_t2str(status), bdaddr2str(bd_addr),
+                       num_properties);
+
+       add_remote_device(bd_addr);
+
+       dump_properties(num_properties, properties);
+}
+
+static void device_found_cb(int num_properties, bt_property_t *properties)
+{
+       haltest_info("%s: num_properties=%d\n", __func__, num_properties);
+
+       add_remote_device_from_props(num_properties, properties);
+
+       dump_properties(num_properties, properties);
+}
+
+static void discovery_state_changed_cb(bt_discovery_state_t state)
+{
+       haltest_info("%s: state=%s\n", __func__,
+                                       bt_discovery_state_t2str(state));
+}
+
+/*
+ * Buffer for remote addres that came from one of bind request.
+ * It's stored for command completion.
+ */
+static char last_remote_addr[MAX_ADDR_STR_LEN];
+static bt_ssp_variant_t last_ssp_variant = (bt_ssp_variant_t) -1;
+
+static bt_bdaddr_t pin_request_addr;
+static void pin_request_answer(char *reply)
+{
+       bt_pin_code_t pin;
+       int accept = 0;
+       int pin_len = strlen(reply);
+
+       if (pin_len > 0) {
+               accept = 1;
+               if (pin_len > 16)
+                       pin_len = 16;
+               memcpy(&pin.pin, reply, pin_len);
+       }
+
+       EXEC(if_bluetooth->pin_reply, &pin_request_addr, accept, pin_len, &pin);
+}
+
+static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+                                                               uint32_t cod)
+{
+       /* Store for command completion */
+       bt_bdaddr_t2str(remote_bd_addr, last_remote_addr);
+       pin_request_addr = *remote_bd_addr;
+
+       haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x\n", __func__,
+                                       last_remote_addr, bd_name->name, cod);
+       terminal_prompt_for("Enter pin: ", pin_request_answer);
+}
+
+/* Variables to store information from ssp_request_cb used for ssp_reply */
+static bt_bdaddr_t ssp_request_addr;
+static bt_ssp_variant_t ssp_request_variant;
+static uint32_t ssp_request_pask_key;
+
+/* Called when user hit enter on prompt for confirmation */
+static void ssp_request_yes_no_answer(char *reply)
+{
+       int accept = *reply == 0 || *reply == 'y' || *reply == 'Y';
+
+       if_bluetooth->ssp_reply(&ssp_request_addr, ssp_request_variant, accept,
+                                                       ssp_request_pask_key);
+}
+
+static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+                               uint32_t cod, bt_ssp_variant_t pairing_variant,
+                               uint32_t pass_key)
+{
+       static char prompt[50];
+
+       /* Store for command completion */
+       bt_bdaddr_t2str(remote_bd_addr, last_remote_addr);
+       last_ssp_variant = pairing_variant;
+
+       haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x pairing_variant=%s pass_key=%d\n",
+                       __func__, last_remote_addr, bd_name->name, cod,
+                       bt_ssp_variant_t2str(pairing_variant), pass_key);
+
+       if (pairing_variant == BT_SSP_VARIANT_PASSKEY_CONFIRMATION) {
+               sprintf(prompt, "Does other device show %d [Y/n] ?", pass_key);
+
+               ssp_request_addr = *remote_bd_addr;
+               ssp_request_variant = pairing_variant;
+               ssp_request_pask_key = pass_key;
+
+               terminal_prompt_for(prompt, ssp_request_yes_no_answer);
+       }
+}
+
+static void bond_state_changed_cb(bt_status_t status,
+                                               bt_bdaddr_t *remote_bd_addr,
+                                               bt_bond_state_t state)
+{
+       haltest_info("%s: status=%s remote_bd_addr=%s state=%s\n", __func__,
+                       bt_status_t2str(status), bdaddr2str(remote_bd_addr),
+                       bt_bond_state_t2str(state));
+}
+
+static void acl_state_changed_cb(bt_status_t status,
+                                               bt_bdaddr_t *remote_bd_addr,
+                                               bt_acl_state_t state)
+{
+       haltest_info("%s: status=%s remote_bd_addr=%s state=%s\n", __func__,
+                       bt_status_t2str(status), bdaddr2str(remote_bd_addr),
+                       bt_acl_state_t2str(state));
+}
+
+static void thread_evt_cb(bt_cb_thread_evt evt)
+{
+       haltest_info("%s: evt=%s\n", __func__, bt_cb_thread_evt2str(evt));
+}
+
+static void dut_mode_recv_cb(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+       haltest_info("%s\n", __func__);
+}
+
+#if PLATFORM_SDK_VERSION > 17
+static void le_test_mode_cb(bt_status_t status, uint16_t num_packets)
+{
+       haltest_info("%s %s %d\n", __func__, bt_state_t2str(status),
+                                                               num_packets);
+}
+#endif
+
+static bt_callbacks_t bt_callbacks = {
+       .size = sizeof(bt_callbacks),
+       .adapter_state_changed_cb = adapter_state_changed_cb,
+       .adapter_properties_cb = adapter_properties_cb,
+       .remote_device_properties_cb = remote_device_properties_cb,
+       .device_found_cb = device_found_cb,
+       .discovery_state_changed_cb = discovery_state_changed_cb,
+       .pin_request_cb = pin_request_cb,
+       .ssp_request_cb = ssp_request_cb,
+       .bond_state_changed_cb = bond_state_changed_cb,
+       .acl_state_changed_cb = acl_state_changed_cb,
+       .thread_evt_cb = thread_evt_cb,
+       .dut_mode_recv_cb = dut_mode_recv_cb,
+#if PLATFORM_SDK_VERSION > 17
+       .le_test_mode_cb = le_test_mode_cb
+#endif
+};
+
+static void init_p(int argc, const char **argv)
+{
+       int err;
+       const hw_module_t *module;
+       hw_device_t *device;
+
+       err = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
+       if (err) {
+               haltest_error("he_get_module returned %d\n", err);
+               return;
+       }
+
+       err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+       if (err) {
+               haltest_error("module->methods->open returned %d\n", err);
+               return;
+       }
+
+       if_bluetooth =
+                   ((bluetooth_device_t *) device)->get_bluetooth_interface();
+       if (!if_bluetooth) {
+               haltest_error("get_bluetooth_interface returned NULL\n");
+               return;
+       }
+
+       EXEC(if_bluetooth->init, &bt_callbacks);
+}
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXECV(if_bluetooth->cleanup);
+
+       if_bluetooth = NULL;
+}
+
+static void enable_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXEC(if_bluetooth->enable);
+}
+
+static void disable_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXEC(if_bluetooth->disable);
+}
+
+static void get_adapter_properties_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXEC(if_bluetooth->get_adapter_properties);
+}
+
+static void get_adapter_property_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(bt_property_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void get_adapter_property_p(int argc, const char **argv)
+{
+       int type;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_PROP_TYPE_ARG(2, type);
+
+       EXEC(if_bluetooth->get_adapter_property, type);
+}
+
+static const char * const names[] = {
+       "BT_PROPERTY_BDNAME",
+       "BT_PROPERTY_ADAPTER_SCAN_MODE",
+       "BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT",
+       NULL
+};
+
+static void set_adapter_property_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = (void *) names;
+               *enum_func = enum_strings;
+       } else if (argc == 4) {
+               if (0 == strcmp(argv[2], "BT_PROPERTY_ADAPTER_SCAN_MODE")) {
+                       *user = TYPE_ENUM(bt_scan_mode_t);
+                       *enum_func = enum_defines;
+               }
+       }
+}
+
+static void set_adapter_property_p(int argc, const char **argv)
+{
+       bt_property_t property;
+       bt_scan_mode_t mode;
+       int timeout;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_PROP_TYPE_ARG(2, property.type);
+
+       if (argc <= 3) {
+               haltest_error("No property value specified\n");
+               return;
+       }
+       switch (property.type) {
+       case BT_PROPERTY_BDNAME:
+               property.len = strlen(argv[3]) + 1;
+               property.val = (char *) argv[3];
+               break;
+
+       case BT_PROPERTY_ADAPTER_SCAN_MODE:
+               mode = str2btscanmode(argv[3]);
+               property.len = sizeof(bt_scan_mode_t);
+               property.val = &mode;
+               break;
+
+       case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+               timeout = atoi(argv[3]);
+               property.val = &timeout;
+               property.len = sizeof(timeout);
+               break;
+
+       default:
+               haltest_error("Invalid property %s\n", argv[3]);
+               return;
+       }
+
+       EXEC(if_bluetooth->set_adapter_property, &property);
+}
+
+/*
+ * This function is to be used for completion methods that need only address
+ */
+static void complete_addr_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
+}
+
+/* Just addres to complete, use complete_addr_c */
+#define get_remote_device_properties_c complete_addr_c
+
+static void get_remote_device_properties_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_bluetooth->get_remote_device_properties, &addr);
+}
+
+static void get_remote_device_property_c(int argc, const char **argv,
+                                                       enum_func *enum_func,
+                                                       void **user)
+{
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(bt_property_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void get_remote_device_property_p(int argc, const char **argv)
+{
+       bt_property_type_t type;
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+       VERIFY_PROP_TYPE_ARG(3, type);
+
+       EXEC(if_bluetooth->get_remote_device_property, &addr, type);
+}
+
+/*
+ * Same completion as for get_remote_device_property_c can be used for
+ * set_remote_device_property_c. No need to create separate function.
+ */
+#define set_remote_device_property_c get_remote_device_property_c
+
+static void set_remote_device_property_p(int argc, const char **argv)
+{
+       bt_property_t property;
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+       VERIFY_PROP_TYPE_ARG(3, property.type);
+
+       switch (property.type) {
+       case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+               property.len = strlen(argv[4]);
+               property.val = (char *) argv[4];
+               break;
+       default:
+               return;
+       }
+
+       EXEC(if_bluetooth->set_remote_device_property, &addr, &property);
+}
+
+/*
+ * For now uuid is not autocompleted. Use routine for complete_addr_c
+ */
+#define get_remote_service_record_c complete_addr_c
+
+static void get_remote_service_record_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bt_uuid_t uuid;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc <= 3) {
+               haltest_error("No uuid specified\n");
+               return;
+       }
+
+       str2bt_uuid_t(argv[3], &uuid);
+
+       EXEC(if_bluetooth->get_remote_service_record, &addr, &uuid);
+}
+
+/* Just addres to complete, use complete_addr_c */
+#define get_remote_services_c complete_addr_c
+
+static void get_remote_services_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_bluetooth->get_remote_services, &addr);
+}
+
+static void start_discovery_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXEC(if_bluetooth->start_discovery);
+}
+
+static void cancel_discovery_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_bluetooth);
+
+       EXEC(if_bluetooth->cancel_discovery);
+}
+
+/* Just addres to complete, use complete_addr_c */
+#define create_bond_c complete_addr_c
+
+static void create_bond_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_bluetooth->create_bond, &addr);
+}
+
+/* Just addres to complete, use complete_addr_c */
+#define remove_bond_c complete_addr_c
+
+static void remove_bond_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_bluetooth->remove_bond, &addr);
+}
+
+/* Just addres to complete, use complete_addr_c */
+#define cancel_bond_c complete_addr_c
+
+static void cancel_bond_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_bluetooth->cancel_bond, &addr);
+}
+
+static void pin_reply_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       static const char *const completions[] = { last_remote_addr, NULL };
+
+       if (argc == 3) {
+               *user = (void *) completions;
+               *enum_func = enum_strings;
+       }
+}
+
+static void pin_reply_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bt_pin_code_t pin;
+       int pin_len = 0;
+       int accept = 0;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc > 3) {
+               accept = 1;
+               pin_len = strlen(argv[3]);
+               memcpy(pin.pin, argv[3], pin_len);
+       }
+
+       EXEC(if_bluetooth->pin_reply, &addr, accept, pin_len, &pin);
+}
+
+static void ssp_reply_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = last_remote_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 5) {
+               *user = "1";
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               if (-1 != (int) last_ssp_variant) {
+                       *user = (void *) bt_ssp_variant_t2str(last_ssp_variant);
+                       *enum_func = enum_one_string;
+               } else {
+                       *user = TYPE_ENUM(bt_ssp_variant_t);
+                       *enum_func = enum_defines;
+               }
+       }
+}
+
+static void ssp_reply_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bt_ssp_variant_t var;
+       int accept;
+       int passkey;
+
+       RETURN_IF_NULL(if_bluetooth);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc < 4) {
+               haltest_error("No ssp variant specified\n");
+               return;
+       }
+
+       var = str2btsspvariant(argv[3]);
+       if (argc < 5) {
+               haltest_error("No accept value specified\n");
+               return;
+       }
+
+       accept = atoi(argv[4]);
+       passkey = 0;
+
+       if (accept && var == BT_SSP_VARIANT_PASSKEY_ENTRY && argc >= 5)
+               passkey = atoi(argv[4]);
+
+       EXEC(if_bluetooth->ssp_reply, &addr, var, accept, passkey);
+}
+
+static void get_profile_interface_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       static const char *const profile_ids[] = {
+               BT_PROFILE_HANDSFREE_ID,
+               BT_PROFILE_ADVANCED_AUDIO_ID,
+               BT_PROFILE_HEALTH_ID,
+               BT_PROFILE_SOCKETS_ID,
+               BT_PROFILE_HIDHOST_ID,
+               BT_PROFILE_PAN_ID,
+#if PLATFORM_SDK_VERSION > 17
+               BT_PROFILE_GATT_ID,
+               BT_PROFILE_AV_RC_ID,
+#endif
+               NULL
+       };
+
+       if (argc == 3) {
+               *user = (void *) profile_ids;
+               *enum_func = enum_strings;
+       }
+}
+
+static void get_profile_interface_p(int argc, const char **argv)
+{
+       const char *id;
+       const void **pif = NULL;
+       const void *dummy = NULL;
+
+       RETURN_IF_NULL(if_bluetooth);
+       if (argc <= 2) {
+               haltest_error("No interface specified\n");
+               return;
+       }
+
+       id = argv[2];
+
+       if (strcmp(BT_PROFILE_HANDSFREE_ID, id) == 0)
+               pif = (const void **) &if_hf;
+       else if (strcmp(BT_PROFILE_ADVANCED_AUDIO_ID, id) == 0)
+               pif = (const void **) &if_av;
+       else if (strcmp(BT_PROFILE_HEALTH_ID, id) == 0)
+               pif = &dummy; /* TODO: change when if_hl is there */
+       else if (strcmp(BT_PROFILE_SOCKETS_ID, id) == 0)
+               pif = (const void **) &if_sock;
+       else if (strcmp(BT_PROFILE_HIDHOST_ID, id) == 0)
+               pif = (const void **) &if_hh;
+       else if (strcmp(BT_PROFILE_PAN_ID, id) == 0)
+               pif = (const void **) &if_pan;
+#if PLATFORM_SDK_VERSION > 17
+       else if (strcmp(BT_PROFILE_AV_RC_ID, id) == 0)
+               pif = &dummy; /* TODO: change when if_rc is there */
+       else if (strcmp(BT_PROFILE_GATT_ID, id) == 0)
+               pif = (const void **) &if_gatt;
+#endif
+       else
+               haltest_error("%s is not correct for get_profile_interface\n",
+                                                                       id);
+
+       if (pif != NULL) {
+               *pif = if_bluetooth->get_profile_interface(id);
+               haltest_info("get_profile_interface(%s) : %p\n", id, *pif);
+       }
+}
+
+static void dut_mode_configure_p(int argc, const char **argv)
+{
+       uint8_t mode;
+
+       RETURN_IF_NULL(if_bluetooth);
+
+       if (argc <= 2) {
+               haltest_error("No dut mode specified\n");
+               return;
+       }
+
+       mode = strtol(argv[2], NULL, 0);
+
+       EXEC(if_bluetooth->dut_mode_configure, mode);
+}
+
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHOD(cleanup),
+       STD_METHOD(enable),
+       STD_METHOD(disable),
+       STD_METHOD(get_adapter_properties),
+       STD_METHODCH(get_adapter_property, "<prop_type>"),
+       STD_METHODCH(set_adapter_property, "<prop_type> <prop_value>"),
+       STD_METHODCH(get_remote_device_properties, "<addr>"),
+       STD_METHODCH(get_remote_device_property, "<addr> <property_type>"),
+       STD_METHODCH(set_remote_device_property,
+                                       "<addr> <property_type> <value>"),
+       STD_METHODCH(get_remote_service_record, "<addr> <uuid>"),
+       STD_METHODCH(get_remote_services, "<addr>"),
+       STD_METHOD(start_discovery),
+       STD_METHOD(cancel_discovery),
+       STD_METHODCH(create_bond, "<addr>"),
+       STD_METHODCH(remove_bond, "<addr>"),
+       STD_METHODCH(cancel_bond, "<addr>"),
+       STD_METHODCH(pin_reply, "<address> [<pin>]"),
+       STD_METHODCH(ssp_reply, "<address> <ssp_veriant> 1|0 [<passkey>]"),
+       STD_METHODCH(get_profile_interface, "<profile id>"),
+       STD_METHODH(dut_mode_configure, "<dut mode>"),
+       END_METHOD
+};
+
+const struct interface bluetooth_if = {
+       .name = "bluetooth",
+       .methods = methods
+};
diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
new file mode 100644 (file)
index 0000000..bb53952
--- /dev/null
@@ -0,0 +1,1758 @@
+/*
+ * Copyright (C) 2013 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 <hardware/bluetooth.h>
+
+#include "../hal-utils.h"
+#include "if-main.h"
+
+const btgatt_interface_t *if_gatt = NULL;
+
+/* In version 19 some callback were changed.
+ * btgatt_char_id_t -> btgatt_gatt_id_t
+ * bt_uuid_t        -> btgatt_gatt_id_t
+ */
+#if PLATFORM_SDK_VERSION > 18
+#define str2btgatt_descr_id_t str2btgatt_gatt_id_t
+#define btgatt_descr_id_t2str btgatt_gatt_id_t2str
+#define btgatt_descr_id_t btgatt_gatt_id_t
+#else
+#define btgatt_descr_id_t2str gatt_uuid_t2str
+#define str2btgatt_descr_id_t(a, b) gatt_str2bt_uuid_t(a, -1, b)
+#define btgatt_gatt_id_t btgatt_char_id_t
+#define btgatt_descr_id_t bt_uuid_t
+#endif
+
+#define MAX_CHAR_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11)
+#define MAX_SRVC_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11 + 1 + 11)
+/* How man characters print from binary objects (arbitrary) */
+#define MAX_HEX_VAL_STR_LEN 100
+#define MAX_NOTIFY_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
+               + MAX_ADDR_STR_LEN + MAX_HEX_VAL_STR_LEN + 60)
+#define MAX_READ_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
+               + MAX_UUID_STR_LEN + MAX_HEX_VAL_STR_LEN + 80)
+
+#define VERIFY_INT_ARG(n, v, err) \
+       do { \
+               if (n < argc) \
+                       v = atoi(argv[n]); \
+               else { \
+                       haltest_error(err); \
+                       return;\
+               } \
+       } while (0)
+
+#define VERIFY_HEX_ARG(n, v, err) \
+       do { \
+               if (n < argc) \
+                       v = strtol(argv[n], NULL, 16); \
+               else { \
+                       haltest_error(err); \
+                       return;\
+               } \
+       } while (0)
+
+/* Helper macros to verify arguments of methods */
+#define VERIFY_CLIENT_IF(n, v) VERIFY_INT_ARG(n, v, "No client_if specified\n")
+#define VERIFY_SERVER_IF(n, v) VERIFY_INT_ARG(n, v, "No server_if specified\n")
+#define VERIFY_CONN_ID(n, v) VERIFY_INT_ARG(n, v, "No conn_if specified\n")
+#define VERIFY_HANDLE(n, v) VERIFY_HEX_ARG(n, v, "No "#v" specified\n")
+#define VERIFY_SERVICE_HANDLE(n, v) VERIFY_HANDLE(n, v)
+
+#define VERIFY_UUID(n, v) \
+       do { \
+               if (n < argc) \
+                       gatt_str2bt_uuid_t(argv[n], -1, v); \
+               else { \
+                       haltest_error("No uuid specified\n"); \
+                       return;\
+               } \
+       } while (0)
+
+#define VERIFY_SRVC_ID(n, v) \
+       do { \
+               if (n < argc) \
+                       str2btgatt_srvc_id_t(argv[n], v); \
+               else { \
+                       haltest_error("No srvc_id specified\n"); \
+                       return;\
+               } \
+       } while (0)
+
+#define VERIFY_CHAR_ID(n, v) \
+       do { \
+               if (n < argc) \
+                       str2btgatt_gatt_id_t(argv[n], v); \
+               else { \
+                       haltest_error("No char_id specified\n"); \
+                       return;\
+               } \
+       } while (0)
+
+#define VERIFY_DESCR_ID(n, v) \
+       do { \
+               if (n < argc) \
+                       str2btgatt_descr_id_t(argv[n], v); \
+               else { \
+                       haltest_error("No descr_id specified\n"); \
+                       return;\
+               } \
+       } while (0)
+
+/* Gatt uses little endian uuid */
+static const char GATT_BASE_UUID[] = {
+       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * converts gatt uuid to string
+ * buf should be at least 39 bytes
+ *
+ * This function formats 16, 32 and 128 bits uuid
+ *
+ * returns string representation of uuid
+ */
+static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
+{
+       int shift = 0;
+       int i = 16;
+       int limit = 0;
+       int j = 0;
+
+       /* for bluetooth uuid only 32 bits */
+       if (0 == memcmp(&uuid->uu, &GATT_BASE_UUID,
+                                               sizeof(bt_uuid_t) - 4)) {
+               limit = 12;
+               /* make it 16 bits */
+               if (uuid->uu[15] == 0 && uuid->uu[14] == 0)
+                       i = 14;
+       }
+
+       while (i-- > limit) {
+               if (i == 11 || i == 9 || i == 7 || i == 5) {
+                       buf[j * 2 + shift] = '-';
+                       shift++;
+               }
+
+               sprintf(buf + j * 2 + shift, "%02x", uuid->uu[i]);
+               ++j;
+       }
+
+       return buf;
+}
+
+/*
+ * Tries to convert hex string of given size into out buffer.
+ * Output buffer is little endian.
+ */
+static void scan_field(const char *str, int len, uint8_t *out, int out_size)
+{
+       int i;
+
+       memset(out, 0, out_size);
+       if (out_size * 2 > len + 1)
+               out_size = (len + 1) / 2;
+
+       for (i = 0; i < out_size && len > 0; ++i) {
+               len -= 2;
+               if (len >= 0)
+                       sscanf(str + len, "%02hhx", &out[i]);
+               else
+                       sscanf(str, "%1hhx", &out[i]);
+       }
+}
+
+/* Like strchr but with upper limit instead of 0 terminated string */
+static const char *strchrlimit(const char *p, const char *e, int c)
+{
+       while (p < e && *p != (char) c)
+               ++p;
+
+       return p < e ? p : NULL;
+}
+
+/*
+ * converts string to uuid
+ * it accepts uuid in following forms:
+ *     123
+ *     0000123
+ *     0000123-0014-1234-0000-000056789abc
+ *     0000123001412340000000056789abc
+ *     123-14-1234-0-56789abc
+ */
+static void gatt_str2bt_uuid_t(const char *str, int len, bt_uuid_t *uuid)
+{
+       int dash_cnt = 0;
+       int dashes[6] = {-1}; /* indexes of '-' or \0 */
+       static uint8_t filed_offset[] = { 16, 12, 10, 8, 6, 0 };
+       const char *p = str;
+       const char *e;
+       int i;
+
+       e = str + ((len >= 0) ? len : (int) strlen(str));
+
+       while (p != NULL && dash_cnt < 5) {
+               const char *f = strchrlimit(p, e, '-');
+
+               if (f != NULL)
+                       dashes[++dash_cnt] = f++ - str;
+               p = f;
+       }
+
+       /* get index of \0 to dashes table */
+       if (dash_cnt < 5)
+               dashes[++dash_cnt] = e - str;
+
+       memcpy(uuid, GATT_BASE_UUID, sizeof(bt_uuid_t));
+
+       /* whole uuid in one string without dashes */
+       if (dash_cnt == 1 && dashes[1] > 8) {
+               if (dashes[1] > 32)
+                       dashes[1] = 32;
+               scan_field(str, dashes[1],
+                               &uuid->uu[16 - (dashes[1] + 1) / 2],
+                               (dashes[1] + 1) / 2);
+       } else {
+               for (i = 0; i < dash_cnt; ++i) {
+                       scan_field(str + dashes[i] + 1,
+                                       dashes[i + 1] - dashes[i] - 1,
+                                       &uuid->uu[filed_offset[i + 1]],
+                                       filed_offset[i] - filed_offset[i + 1]);
+               }
+       }
+}
+
+/* char_id formating function */
+static char *btgatt_gatt_id_t2str(const btgatt_gatt_id_t *char_id, char *buf)
+{
+       char uuid_buf[MAX_UUID_STR_LEN];
+
+       sprintf(buf, "{%s,%d}", gatt_uuid_t2str(&char_id->uuid, uuid_buf),
+                                                       char_id->inst_id);
+       return buf;
+}
+
+/* Parse btgatt_gatt_id_t */
+static void str2btgatt_gatt_id_t(const char *buf, btgatt_gatt_id_t *char_id)
+{
+       const char *e;
+
+       memcpy(&char_id->uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+       char_id->inst_id = 0;
+
+       if (*buf == '{')
+               buf++;
+       e = strpbrk(buf, " ,}");
+       if (e == NULL)
+               e = buf + strlen(buf);
+
+       gatt_str2bt_uuid_t(buf, e - buf, &char_id->uuid);
+       if (*e == ',') {
+               buf = e + 1;
+               e = strpbrk(buf, " ,}");
+               if (e == NULL)
+                       e = buf + strlen(buf);
+               if (buf < e)
+                       char_id->inst_id = atoi(buf);
+       }
+}
+
+/* service_id formating function */
+static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
+{
+       char uuid_buf[MAX_UUID_STR_LEN];
+
+       sprintf(buf, "{%s,%d,%d}", gatt_uuid_t2str(&srvc_id->id.uuid, uuid_buf),
+                               srvc_id->id.inst_id, srvc_id->is_primary);
+       return buf;
+}
+
+/* Parse btgatt_srvc_id_t */
+static void str2btgatt_srvc_id_t(const char *buf, btgatt_srvc_id_t *srvc_id)
+{
+       const char *e;
+
+       memcpy(&srvc_id->id.uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+       srvc_id->id.inst_id = 0;
+       srvc_id->is_primary = 1;
+
+       if (*buf == '{')
+               buf++;
+       e = strpbrk(buf, " ,}");
+       if (e == NULL)
+               e = buf + strlen(buf);
+
+       gatt_str2bt_uuid_t(buf, e - buf, &srvc_id->id.uuid);
+       if (*e == ',') {
+               buf = e + 1;
+               e = strpbrk(buf, " ,}");
+               if (e == NULL)
+                       e = buf + strlen(buf);
+               if (buf < e)
+                       srvc_id->id.inst_id = atoi(buf);
+       }
+
+       if (*e == ',') {
+               buf = e + 1;
+               e = strpbrk(buf, " ,}");
+               if (e == NULL)
+                       e = buf + strlen(buf);
+               if (buf < e)
+                       srvc_id->is_primary = atoi(buf);
+       }
+}
+
+/* Converts array of uint8_t to string representation */
+static char *array2str(const uint8_t *v, int size, char *buf, int out_size)
+{
+       int limit = size;
+       int i;
+
+       if (out_size > 0) {
+               *buf = '\0';
+               if (size >= 2 * out_size)
+                       limit = (out_size - 2) / 2;
+
+               for (i = 0; i < limit; ++i)
+                       sprintf(buf + 2 * i, "%02x", v[i]);
+
+               /* output buffer not enough to hold whole field fill with ...*/
+               if (limit < size)
+                       sprintf(buf + 2 * i, "...");
+       }
+
+       return buf;
+}
+
+/* Converts btgatt_notify_params_t to string */
+static char *btgatt_notify_params_t2str(const btgatt_notify_params_t *data,
+                                                               char *buf)
+{
+       char addr[MAX_ADDR_STR_LEN];
+       char srvc_id[MAX_SRVC_ID_STR_LEN];
+       char char_id[MAX_CHAR_ID_STR_LEN];
+       char value[MAX_HEX_VAL_STR_LEN];
+
+       sprintf(buf, "{bda=%s, srvc_id=%s, char_id=%s, val=%s, is_notify=%u}",
+               bt_bdaddr_t2str(&data->bda, addr),
+               btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
+               btgatt_gatt_id_t2str(&data->char_id, char_id),
+               array2str(data->value, data->len, value, sizeof(value)),
+                                                       data->is_notify);
+       return buf;
+}
+
+static char *btgatt_unformatted_value_t2str(const btgatt_unformatted_value_t *v,
+                                                       char *buf, int size)
+{
+       return array2str(v->value, v->len, buf, size);
+}
+
+static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
+                                                               char *buf)
+{
+       char srvc_id[MAX_SRVC_ID_STR_LEN];
+       char char_id[MAX_CHAR_ID_STR_LEN];
+       char descr_id[MAX_UUID_STR_LEN];
+       char value[MAX_HEX_VAL_STR_LEN];
+
+       sprintf(buf, "{srvc_id=%s, char_id=%s, descr_id=%s, val=%s value_type=%d, status=%d}",
+               btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
+               btgatt_gatt_id_t2str(&data->char_id, char_id),
+               btgatt_descr_id_t2str(&data->descr_id, descr_id),
+               btgatt_unformatted_value_t2str(&data->value, value, 100),
+               data->value_type, data->status);
+       return buf;
+}
+
+/* BT-GATT Client callbacks. */
+
+/* Cache client_if and conn_id for tab completion */
+static char client_if_str[20];
+static char conn_id_str[20];
+/* Cache address for tab completion */
+static char last_addr[MAX_ADDR_STR_LEN];
+
+/* Callback invoked in response to register_client */
+static void gattc_register_client_cb(int status, int client_if,
+                                                       bt_uuid_t *app_uuid)
+{
+       char buf[MAX_UUID_STR_LEN];
+
+       snprintf(client_if_str, sizeof(client_if_str), "%d", client_if);
+
+       haltest_info("%s: status=%d client_if=%d app_uuid=%s\n", __func__,
+                                               status, client_if,
+                                               gatt_uuid_t2str(app_uuid, buf));
+}
+
+/* Callback for scan results */
+static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
+{
+       char buf[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: bda=%s rssi=%d adv_data=%p\n", __func__,
+                               bt_bdaddr_t2str(bda, buf), rssi, adv_data);
+}
+
+/* GATT open callback invoked in response to open */
+static void gattc_connect_cb(int conn_id, int status, int client_if,
+                                                       bt_bdaddr_t *bda)
+{
+       haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
+                                       __func__, conn_id, status, client_if,
+                                       bt_bdaddr_t2str(bda, last_addr));
+}
+
+/* Callback invoked in response to close */
+static void gattc_disconnect_cb(int conn_id, int status, int client_if,
+                                                       bt_bdaddr_t *bda)
+{
+       char buf[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
+                                       __func__, conn_id, status, client_if,
+                                       bt_bdaddr_t2str(bda, buf));
+}
+
+/*
+ * Invoked in response to search_service when the GATT service search
+ * has been completed.
+ */
+static void gattc_search_complete_cb(int conn_id, int status)
+{
+       haltest_info("%s: conn_id=%d status=%s\n", __func__, conn_id, status);
+}
+
+/* Reports GATT services on a remote device */
+static void gattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id)
+{
+       char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+
+       haltest_info("%s: conn_id=%d srvc_id=%s\n", __func__, conn_id,
+                               btgatt_srvc_id_t2str(srvc_id, srvc_id_buf));
+}
+
+/* GATT characteristic enumeration result callback */
+static void gattc_get_characteristic_cb(int conn_id, int status,
+                                       btgatt_srvc_id_t *srvc_id,
+                                       btgatt_gatt_id_t *char_id,
+                                       int char_prop)
+{
+       char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+       char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, char_prop=%x\n",
+                       __func__, conn_id, status,
+                       btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+                       btgatt_gatt_id_t2str(char_id, char_id_buf), char_prop);
+
+       /* enumerate next characteristic */
+       if (status == 0)
+               EXEC(if_gatt->client->get_characteristic, conn_id, srvc_id,
+                                                               char_id);
+}
+
+/* GATT descriptor enumeration result callback */
+static void gattc_get_descriptor_cb(int conn_id, int status,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               btgatt_descr_id_t *descr_id)
+{
+       char buf[MAX_UUID_STR_LEN];
+       char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+       char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, descr_id=%s\n",
+                               __func__, conn_id, status,
+                               btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+                               btgatt_gatt_id_t2str(char_id, char_id_buf),
+                               btgatt_descr_id_t2str(descr_id, buf));
+
+       if (status == 0)
+               EXEC(if_gatt->client->get_descriptor, conn_id, srvc_id, char_id,
+                                                               descr_id);
+}
+
+/* GATT included service enumeration result callback */
+static void gattc_get_included_service_cb(int conn_id, int status,
+                                               btgatt_srvc_id_t *srvc_id,
+                                               btgatt_srvc_id_t *incl_srvc_id)
+{
+       char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+       char incl_srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d srvc_id=%s incl_srvc_id=%s)\n",
+                       __func__, conn_id, status,
+                       btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+                       btgatt_srvc_id_t2str(incl_srvc_id, incl_srvc_id_buf));
+
+       if (status == 0)
+               EXEC(if_gatt->client->get_included_service, conn_id, srvc_id,
+                                                               incl_srvc_id);
+}
+
+/* Callback invoked in response to [de]register_for_notification */
+static void gattc_register_for_notification_cb(int conn_id, int registered,
+                                               int status,
+                                               btgatt_srvc_id_t *srvc_id,
+                                               btgatt_gatt_id_t *char_id)
+{
+       char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+       char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+       haltest_info("%s: conn_id=%d registered=%d status=%d srvc_id=%s char_id=%s\n",
+                               __func__, conn_id, registered, status,
+                               btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+                               btgatt_gatt_id_t2str(char_id, char_id_buf));
+}
+
+/*
+ * Remote device notification callback, invoked when a remote device sends
+ * a notification or indication that a client has registered for.
+ */
+static void gattc_notify_cb(int conn_id, btgatt_notify_params_t *p_data)
+{
+       char buf[MAX_NOTIFY_PARAMS_STR_LEN];
+
+       haltest_info("%s: conn_id=%d data=%s\n", __func__, conn_id,
+                               btgatt_notify_params_t2str(p_data, buf));
+}
+
+/* Reports result of a GATT read operation */
+static void gattc_read_characteristic_cb(int conn_id, int status,
+                                               btgatt_read_params_t *p_data)
+{
+       char buf[MAX_READ_PARAMS_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
+                               status, btgatt_read_params_t2str(p_data, buf));
+}
+
+/* GATT write characteristic operation callback */
+static void gattc_write_characteristic_cb(int conn_id, int status,
+                                               btgatt_write_params_t *p_data)
+{
+       haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
+}
+
+/* GATT execute prepared write callback */
+static void gattc_execute_write_cb(int conn_id, int status)
+{
+       haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
+}
+
+/* Callback invoked in response to read_descriptor */
+static void gattc_read_descriptor_cb(int conn_id, int status,
+                                               btgatt_read_params_t *p_data)
+{
+       char buf[MAX_READ_PARAMS_STR_LEN];
+
+       haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
+                               status, btgatt_read_params_t2str(p_data, buf));
+}
+
+/* Callback invoked in response to write_descriptor */
+static void gattc_write_descriptor_cb(int conn_id, int status,
+                                               btgatt_write_params_t *p_data)
+{
+       haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
+}
+
+/* Callback triggered in response to read_remote_rssi */
+static void gattc_read_remote_rssi_cb(int client_if, bt_bdaddr_t *bda, int rssi,
+                                                               int status)
+{
+       char buf[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: client_if=%d bda=%s rssi=%d satus=%d\n", __func__,
+                       client_if, bt_bdaddr_t2str(bda, buf), rssi, status);
+}
+
+static const btgatt_client_callbacks_t btgatt_client_callbacks = {
+       .register_client_cb = gattc_register_client_cb,
+       .scan_result_cb = gattc_scan_result_cb,
+       .open_cb = gattc_connect_cb,
+       .close_cb = gattc_disconnect_cb,
+       .search_complete_cb = gattc_search_complete_cb,
+       .search_result_cb = gattc_search_result_cb,
+       .get_characteristic_cb = gattc_get_characteristic_cb,
+       .get_descriptor_cb = gattc_get_descriptor_cb,
+       .get_included_service_cb = gattc_get_included_service_cb,
+       .register_for_notification_cb = gattc_register_for_notification_cb,
+       .notify_cb = gattc_notify_cb,
+       .read_characteristic_cb = gattc_read_characteristic_cb,
+       .write_characteristic_cb = gattc_write_characteristic_cb,
+       .read_descriptor_cb = gattc_read_descriptor_cb,
+       .write_descriptor_cb = gattc_write_descriptor_cb,
+       .execute_write_cb = gattc_execute_write_cb,
+       .read_remote_rssi_cb = gattc_read_remote_rssi_cb
+};
+
+/* BT-GATT Server callbacks */
+
+/* Cache server_if and conn_id for tab completion */
+static char server_if_str[20];
+
+/* Callback invoked in response to register_server */
+static void gatts_register_server_cb(int status, int server_if,
+                                                       bt_uuid_t *app_uuid)
+{
+       char buf[MAX_UUID_STR_LEN];
+
+       haltest_info("%s: status=%d server_if=%d app_uuid=%s\n", __func__,
+                       status, server_if, gatt_uuid_t2str(app_uuid, buf));
+}
+
+/*
+ * Callback indicating that a remote device has connected
+ * or been disconnected
+ */
+static void gatts_connection_cb(int conn_id, int server_if, int connected,
+                                                       bt_bdaddr_t *bda)
+{
+       haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
+                                       __func__, conn_id, server_if, connected,
+                                       bt_bdaddr_t2str(bda, last_addr));
+       snprintf(conn_id_str, sizeof(conn_id_str), "%d", conn_id);
+}
+
+/* Callback invoked in response to create_service */
+static void gatts_service_added_cb(int status, int server_if,
+                               btgatt_srvc_id_t *srvc_id, int srvc_handle)
+{
+       char buf[MAX_SRVC_ID_STR_LEN];
+
+       snprintf(server_if_str, sizeof(server_if_str), "%d", server_if);
+
+       haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=%x\n",
+                       __func__, status, server_if,
+                       btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
+}
+
+/* Callback indicating that an included service has been added to a service */
+static void gatts_included_service_added_cb(int status, int server_if,
+                                                       int srvc_handle,
+                                                       int incl_srvc_handle)
+{
+       haltest_info("%s: status=%d server_if=%d srvc_handle=%x inc_srvc_handle=%x\n",
+                                               __func__, status, server_if,
+                                               srvc_handle, incl_srvc_handle);
+}
+
+/* Callback invoked when a characteristic has been added to a service */
+static void gatts_characteristic_added_cb(int status, int server_if,
+                                                               bt_uuid_t *uuid,
+                                                               int srvc_handle,
+                                                               int char_handle)
+{
+       char buf[MAX_SRVC_ID_STR_LEN];
+
+       haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x char_handle=%x\n",
+                       __func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+                       srvc_handle, char_handle);
+}
+
+/* Callback invoked when a descriptor has been added to a characteristic */
+static void gatts_descriptor_added_cb(int status, int server_if,
+                                       bt_uuid_t *uuid, int srvc_handle,
+                                                       int descr_handle)
+{
+       char buf[MAX_SRVC_ID_STR_LEN];
+
+       haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x descr_handle=%x\n",
+                       __func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+                       srvc_handle, descr_handle);
+}
+
+/* Callback invoked in response to start_service */
+static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
+{
+       haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+                               __func__, status, server_if, srvc_handle);
+}
+
+/* Callback invoked in response to stop_service */
+static void gatts_service_stopped_cb(int status, int server_if, int srvc_handle)
+{
+       haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+                               __func__, status, server_if, srvc_handle);
+}
+
+/* Callback triggered when a service has been deleted */
+static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
+{
+       haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+                               __func__, status, server_if, srvc_handle);
+}
+
+/*
+ * Callback invoked when a remote device has requested to read a characteristic
+ * or descriptor. The application must respond by calling send_response
+ */
+static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                                               int attr_handle, int offset,
+                                               bool is_long)
+{
+       char buf[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d is_long=%d\n",
+                       __func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+                       attr_handle, offset, is_long);
+}
+
+/*
+ * Callback invoked when a remote device has requested to write to a
+ * characteristic or descriptor.
+ */
+static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                                       int attr_handle, int offset, int length,
+                                       bool need_rsp, bool is_prep,
+                                       uint8_t *value)
+{
+       char buf[MAX_ADDR_STR_LEN];
+       char valbuf[100];
+
+       haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d length=%d need_rsp=%d is_prep=%d value=%s\n",
+                       __func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+                       attr_handle, offset, length, need_rsp, is_prep,
+                       array2str(value, length, valbuf, sizeof(valbuf)));
+}
+
+/* Callback invoked when a previously prepared write is to be executed */
+static void gatts_request_exec_write_cb(int conn_id, int trans_id,
+                                       bt_bdaddr_t *bda, int exec_write)
+{
+       char buf[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: conn_id=%d trans_id=%d bda=%s exec_write=%d\n",
+                       __func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+                       exec_write);
+}
+
+/*
+ * Callback triggered in response to send_response if the remote device
+ * sends a confirmation.
+ */
+static void gatts_response_confirmation_cb(int status, int handle)
+{
+       haltest_info("%s: status=%d handle=%x\n", __func__, status, handle);
+}
+
+static const btgatt_server_callbacks_t btgatt_server_callbacks = {
+       .register_server_cb = gatts_register_server_cb,
+       .connection_cb = gatts_connection_cb,
+       .service_added_cb = gatts_service_added_cb,
+       .included_service_added_cb = gatts_included_service_added_cb,
+       .characteristic_added_cb = gatts_characteristic_added_cb,
+       .descriptor_added_cb = gatts_descriptor_added_cb,
+       .service_started_cb = gatts_service_started_cb,
+       .service_stopped_cb = gatts_service_stopped_cb,
+       .service_deleted_cb = gatts_service_deleted_cb,
+       .request_read_cb = gatts_request_read_cb,
+       .request_write_cb = gatts_request_write_cb,
+       .request_exec_write_cb = gatts_request_exec_write_cb,
+       .response_confirmation_cb = gatts_response_confirmation_cb
+};
+
+static const btgatt_callbacks_t gatt_cbacks = {
+       .size = sizeof(gatt_cbacks),
+       .client = &btgatt_client_callbacks,
+       .server = &btgatt_server_callbacks
+};
+
+/* gatt client methods */
+
+/* init */
+
+static void init_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_gatt);
+
+       EXEC(if_gatt->init, &gatt_cbacks);
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_gatt);
+
+       EXECV(if_gatt->cleanup);
+
+       if_gatt = NULL;
+}
+
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHOD(cleanup),
+       END_METHOD
+};
+
+const struct interface gatt_if = {
+       .name = "gatt",
+       .methods = methods
+};
+
+/* register_client */
+
+static void register_client_p(int argc, const char **argv)
+{
+       bt_uuid_t uuid;
+
+       RETURN_IF_NULL(if_gatt);
+
+       /* uuid */
+       if (argc <= 2)
+               gatt_str2bt_uuid_t("babe4bed", -1, &uuid);
+       else
+               gatt_str2bt_uuid_t(argv[2], -1, &uuid);
+
+       EXEC(if_gatt->client->register_client, &uuid);
+}
+
+/* unregister_client */
+
+static void unregister_client_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void unregister_client_p(int argc, const char **argv)
+{
+       int client_if;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+
+       EXEC(if_gatt->client->unregister_client, client_if);
+}
+
+/* scan */
+
+/* Same completion as unregister for now, start stop is not auto completed */
+#define scan_c unregister_client_c
+
+static void scan_p(int argc, const char **argv)
+{
+       int client_if;
+       int start = 1;
+
+       RETURN_IF_NULL(if_gatt);
+
+       VERIFY_CLIENT_IF(2, client_if);
+
+       /* start */
+       if (argc >= 3)
+               start = atoi(argv[3]);
+
+       EXEC(if_gatt->client->scan, client_if, start);
+}
+
+/* connect */
+
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+       int is_direct = 1;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+
+       /* is_direct */
+       if (argc > 4)
+               is_direct = atoi(argv[4]);
+
+       EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct);
+}
+
+/* disconnect */
+
+static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = last_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 5) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void disconnect_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+       int conn_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+       VERIFY_CONN_ID(4, conn_id);
+
+       EXEC(if_gatt->client->disconnect, client_if, &bd_addr, conn_id);
+}
+
+/* refresh */
+
+static void refresh_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *enum_func = enum_devices;
+       }
+}
+
+static void refresh_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+
+       EXEC(if_gatt->client->refresh, client_if, &bd_addr);
+}
+
+/* search_service */
+
+static void search_service_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void search_service_p(int argc, const char **argv)
+{
+       int conn_id;
+       bt_uuid_t filter_uuid;
+
+       RETURN_IF_NULL(if_gatt);
+
+       VERIFY_CONN_ID(2, conn_id);
+
+       /* uuid */
+       if (argc <= 3)
+               memset(&filter_uuid, 0, sizeof(bt_uuid_t));
+       else
+               gatt_str2bt_uuid_t(argv[3], -1, &filter_uuid);
+
+       EXEC(if_gatt->client->search_service, conn_id, &filter_uuid);
+}
+
+/* get_included_service */
+
+static void get_included_service_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void get_included_service_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+
+       EXEC(if_gatt->client->get_included_service, conn_id, &srvc_id, NULL);
+}
+
+/* get_characteristic */
+
+/* Same completion as get_included_service_c */
+#define get_characteristic_c get_included_service_c
+
+static void get_characteristic_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+
+       EXEC(if_gatt->client->get_characteristic, conn_id, &srvc_id, NULL);
+}
+
+/* get_descriptor */
+
+/* Same completion as get_included_service_c */
+#define get_descriptor_c get_included_service_c
+
+static void get_descriptor_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+       VERIFY_CHAR_ID(4, &char_id);
+
+       EXEC(if_gatt->client->get_descriptor, conn_id, &srvc_id, &char_id,
+                                                                       NULL);
+}
+
+/* read_characteristic */
+
+/* Same completion as get_included_service_c */
+#define read_characteristic_c get_included_service_c
+
+static void read_characteristic_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+       int auth_req = 0;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+       VERIFY_CHAR_ID(4, &char_id);
+
+       /* auth_req */
+       if (argc > 5)
+               auth_req = atoi(argv[5]);
+
+       EXEC(if_gatt->client->read_characteristic, conn_id, &srvc_id, &char_id,
+                                                               auth_req);
+}
+
+/* write_characteristic */
+
+static void write_characteristic_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       /*
+        * This should be from tGATT_WRITE_TYPE but it's burried
+        * inside bluedroid guts
+        */
+       static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+       if (argc == 3) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 6) {
+               *user = wrtypes;
+               *enum_func = enum_strings;
+       }
+}
+
+static void write_characteristic_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+       int write_type;
+       int len;
+       int auth_req = 0;
+       uint8_t value[100];
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+       VERIFY_CHAR_ID(4, &char_id);
+
+       /* write type */
+       if (argc <= 5) {
+               haltest_error("No write type specified\n");
+               return;
+       }
+       write_type = atoi(argv[5]);
+
+       /* value */
+       if (argc <= 6) {
+               haltest_error("No value specified\n");
+               return;
+       }
+
+       /* len in chars */
+       len = strlen(argv[6]);
+       scan_field(argv[6], len, value, sizeof(value));
+       /* len in bytes converted from ascii chars */
+       len = (len + 1) / 2;
+
+       /* auth_req */
+       if (argc > 7)
+               auth_req = atoi(argv[7]);
+
+       EXEC(if_gatt->client->write_characteristic, conn_id, &srvc_id, &char_id,
+                               write_type, len, auth_req, (char *) value);
+}
+
+/* read_descriptor */
+
+/* Same completion as get_included_service_c */
+#define read_descriptor_c get_included_service_c
+
+static void read_descriptor_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+       btgatt_descr_id_t descr_id;
+       int auth_req = 0;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+       VERIFY_CHAR_ID(4, &char_id);
+       VERIFY_DESCR_ID(5, &descr_id);
+
+       /* auth_req */
+       if (argc > 6)
+               auth_req = atoi(argv[6]);
+
+       EXEC(if_gatt->client->read_descriptor, conn_id, &srvc_id, &char_id,
+                                                       &descr_id, auth_req);
+}
+
+/* write_descriptor */
+
+static void write_descriptor_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       /*
+        * This should be from tGATT_WRITE_TYPE but it's burried
+        * inside bluedroid guts
+        */
+       static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+       if (argc == 3) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 7) {
+               *user = wrtypes;
+               *enum_func = enum_strings;
+       }
+}
+
+static void write_descriptor_p(int argc, const char **argv)
+{
+       int conn_id;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+       btgatt_descr_id_t descr_id;
+       int write_type;
+       int len;
+       int auth_req = 0;
+       uint8_t value[200] = {0};
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+       VERIFY_SRVC_ID(3, &srvc_id);
+       VERIFY_CHAR_ID(4, &char_id);
+       VERIFY_DESCR_ID(5, &descr_id);
+
+       /* write type */
+       if (argc <= 6) {
+               haltest_error("No write type specified\n");
+               return;
+       }
+       write_type = atoi(argv[6]);
+
+       /* value */
+       if (argc <= 7) {
+               haltest_error("No value specified\n");
+               return;
+       }
+
+       /* len in chars */
+       len = strlen(argv[7]);
+       scan_field(argv[7], len, value, sizeof(value));
+       /* len in bytes converted from ascii chars */
+       len = (len + 1) / 2;
+
+       /* auth_req */
+       if (argc > 8)
+               auth_req = atoi(argv[8]);
+
+       EXEC(if_gatt->client->write_descriptor, conn_id, &srvc_id, &char_id,
+                       &descr_id, write_type, len, auth_req, (char *) value);
+}
+
+/* execute_write */
+
+/* Same completion as search_service */
+#define execute_write_c search_service_c
+
+static void execute_write_p(int argc, const char **argv)
+{
+       int conn_id;
+       int execute;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CONN_ID(2, conn_id);
+
+       /* execute */
+       if (argc <= 3) {
+               haltest_error("No execute specified\n");
+               return;
+       }
+       execute = atoi(argv[3]);
+
+       EXEC(if_gatt->client->execute_write, conn_id, execute);
+}
+
+/* register_for_notification */
+
+static void register_for_notification_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = last_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void register_for_notification_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+       VERIFY_SRVC_ID(4, &srvc_id);
+       VERIFY_CHAR_ID(5, &char_id);
+
+       EXEC(if_gatt->client->register_for_notification, client_if, &bd_addr,
+                                                       &srvc_id, &char_id);
+}
+
+/* deregister_for_notification */
+
+/* Same completion as search_service */
+#define deregister_for_notification_c register_for_notification_c
+
+static void deregister_for_notification_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+       VERIFY_SRVC_ID(4, &srvc_id);
+       VERIFY_CHAR_ID(5, &char_id);
+
+       EXEC(if_gatt->client->deregister_for_notification, client_if, &bd_addr,
+                                                       &srvc_id, &char_id);
+}
+
+/* read_remote_rssi */
+
+static void read_remote_rssi_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = client_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *enum_func = enum_devices;
+       }
+}
+
+static void read_remote_rssi_p(int argc, const char **argv)
+{
+       int client_if;
+       bt_bdaddr_t bd_addr;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_CLIENT_IF(2, client_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+
+       EXEC(if_gatt->client->read_remote_rssi, client_if, &bd_addr);
+}
+
+/* get_device_type */
+
+static void get_device_type_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3)
+               *enum_func = enum_devices;
+}
+
+static void get_device_type_p(int argc, const char **argv)
+{
+       bt_bdaddr_t bd_addr;
+       int dev_type;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_ADDR_ARG(2, &bd_addr);
+
+       dev_type = if_gatt->client->get_device_type(&bd_addr);
+       haltest_info("%s: %d\n", "get_device_type", dev_type);
+}
+
+/* test_command */
+
+static void test_command_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 4)
+               *enum_func = enum_devices;
+}
+
+static void test_command_p(int argc, const char **argv)
+{
+       int command;
+       int i;
+       bt_bdaddr_t bd_addr;
+       bt_uuid_t uuid;
+       btgatt_test_params_t params = {
+               .bda1 = &bd_addr,
+               .uuid1 = &uuid
+       };
+       uint16_t *u = &params.u1;
+
+       RETURN_IF_NULL(if_gatt);
+
+       /* command */
+       if (argc <= 2) {
+               haltest_error("No command specified\n");
+               return;
+       }
+       command = atoi(argv[2]);
+
+       VERIFY_ADDR_ARG(3, &bd_addr);
+       VERIFY_UUID(4, &uuid);
+
+       for (i = 5; i < argc; i++)
+               *u++ = atoi(argv[i]);
+
+       EXEC(if_gatt->client->test_command, command, &params);
+}
+
+static struct method client_methods[] = {
+       STD_METHODH(register_client, "[<uuid>]"),
+       STD_METHODCH(unregister_client, "<client_if>"),
+       STD_METHODCH(scan, "<client_if> [1|0]"),
+       STD_METHODCH(connect, "<client_if> <addr> [<is_direct>]"),
+       STD_METHODCH(disconnect, "<client_if> <addr> <conn_id>"),
+       STD_METHODCH(refresh, "<client_if> <addr>"),
+       STD_METHODCH(search_service, "<conn_id> [<uuid>]"),
+       STD_METHODCH(get_included_service, "<conn_id> <srvc_id>"),
+       STD_METHODCH(get_characteristic, "<conn_id> <srvc_id>"),
+       STD_METHODCH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
+       STD_METHODCH(read_characteristic,
+                       "<conn_id> <srvc_id> <char_id> [<auth_req>]"),
+       STD_METHODCH(write_characteristic,
+                       "<conn_id> <srvc_id> <char_id> <write_type> <hex_value> [<auth_req>]"),
+       STD_METHODCH(read_descriptor,
+                       "<conn_id> <srvc_id> <char_id> <descr_id> [<auth_req>]"),
+       STD_METHODCH(write_descriptor,
+                       "<conn_id> <srvc_id> <char_id> <descr_id> <write_type> <hex_value> [<auth_req>]"),
+       STD_METHODCH(execute_write, "<conn_id> <execute>"),
+       STD_METHODCH(register_for_notification,
+                       "<client_if> <addr> <srvc_id> <char_id>"),
+       STD_METHODCH(deregister_for_notification,
+                       "<client_if> <addr> <srvc_id> <char_id>"),
+       STD_METHODCH(read_remote_rssi, "<client_if> <addr>"),
+       STD_METHODCH(get_device_type, "<addr>"),
+       STD_METHODCH(test_command,
+                       "<cmd> <addr> <uuid> [u1] [u2] [u3] [u4] [u5]"),
+       END_METHOD
+};
+
+const struct interface gatt_client_if = {
+       .name = "gattc",
+       .methods = client_methods
+};
+
+/* gatt server methods */
+
+/* register_server */
+
+static void gatts_register_server_p(int argc, const char *argv[])
+{
+       bt_uuid_t uuid;
+
+       RETURN_IF_NULL(if_gatt);
+
+       /* uuid */
+       if (argc <= 2)
+               gatt_str2bt_uuid_t("bed4babe", -1, &uuid);
+       else
+               gatt_str2bt_uuid_t(argv[2], -1, &uuid);
+
+       EXEC(if_gatt->server->register_server, &uuid);
+}
+
+/* unregister_server */
+
+static void gatts_unregister_server_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = server_if_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void gatts_unregister_server_p(int argc, const char *argv[])
+{
+       int server_if;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+
+       EXEC(if_gatt->server->unregister_server, server_if);
+}
+
+/* connect */
+
+static void gatts_connect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = server_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
+}
+
+static void gatts_connect_p(int argc, const char *argv[])
+{
+       int server_if;
+       bt_bdaddr_t bd_addr;
+       int is_direct = 1;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+
+       /* is_direct */
+       if (argc > 4)
+               is_direct = atoi(argv[4]);
+
+       EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct);
+}
+
+/* disconnect */
+
+static void gatts_disconnect_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = server_if_str;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = last_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 5) {
+               *user = conn_id_str;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void gatts_disconnect_p(int argc, const char *argv[])
+{
+       int server_if;
+       bt_bdaddr_t bd_addr;
+       int conn_id;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_ADDR_ARG(3, &bd_addr);
+       VERIFY_CONN_ID(4, conn_id);
+
+       EXEC(if_gatt->server->disconnect, server_if, &bd_addr, conn_id);
+}
+
+/* add_service */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_service_c gatts_unregister_server_c
+
+static void gatts_add_service_p(int argc, const char *argv[])
+{
+       int server_if;
+       btgatt_srvc_id_t srvc_id;
+       int num_handles;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SRVC_ID(3, &srvc_id);
+
+       /* num handles */
+       if (argc <= 4) {
+               haltest_error("No num_handles specified\n");
+               return;
+       }
+       num_handles = atoi(argv[4]);
+
+       EXEC(if_gatt->server->add_service, server_if, &srvc_id, num_handles);
+}
+
+/* add_included_service */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_included_service_c gatts_unregister_server_c
+
+static void gatts_add_included_service_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+       int included_handle;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+       VERIFY_HANDLE(4, included_handle);
+
+       EXEC(if_gatt->server->add_included_service, server_if, service_handle,
+                                                       included_handle);
+}
+
+/* add_characteristic */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_characteristic_c gatts_unregister_server_c
+
+static void gatts_add_characteristic_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+       int properties;
+       int permissions;
+       bt_uuid_t uuid;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+       VERIFY_UUID(4, &uuid);
+
+       /* properties */
+       if (argc <= 5) {
+               haltest_error("No properties specified\n");
+               return;
+       }
+       properties = atoi(argv[5]);
+
+       /* permissions */
+       if (argc <= 6) {
+               haltest_error("No permissions specified\n");
+               return;
+       }
+       permissions = atoi(argv[6]);
+
+       EXEC(if_gatt->server->add_characteristic, server_if, service_handle,
+                                               &uuid, properties, permissions);
+}
+
+/* add_descriptor */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_descriptor_c gatts_unregister_server_c
+
+static void gatts_add_descriptor_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+       int permissions;
+       bt_uuid_t uuid;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+       VERIFY_UUID(4, &uuid);
+
+       /* permissions */
+       if (argc <= 5) {
+               haltest_error("No permissions specified\n");
+               return;
+       }
+       permissions = atoi(argv[5]);
+
+       EXEC(if_gatt->server->add_descriptor, server_if, service_handle, &uuid,
+                                                               permissions);
+}
+
+/* start_service */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_start_service_c gatts_unregister_server_c
+
+static void gatts_start_service_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+       int transport;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+
+       /* transport */
+       if (argc <= 4) {
+               haltest_error("No transport specified\n");
+               return;
+       }
+       transport = atoi(argv[4]);
+
+       EXEC(if_gatt->server->start_service, server_if, service_handle,
+                                                               transport);
+}
+
+/* stop_service */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_stop_service_c gatts_unregister_server_c
+
+static void gatts_stop_service_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+
+       EXEC(if_gatt->server->stop_service, server_if, service_handle);
+}
+
+/* delete_service */
+
+/* Same completion as gatts_unregister_server_c */
+#define gatts_delete_service_c gatts_unregister_server_c
+
+static void gatts_delete_service_p(int argc, const char *argv[])
+{
+       int server_if;
+       int service_handle;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_SERVICE_HANDLE(3, service_handle);
+
+       EXEC(if_gatt->server->delete_service, server_if, service_handle);
+}
+
+/* send_indication */
+
+static void gatts_send_indication_p(int argc, const char *argv[])
+{
+       int server_if;
+       int attr_handle;
+       int conn_id;
+       int confirm;
+       char data[200];
+       int len = 0;
+
+       RETURN_IF_NULL(if_gatt);
+       VERIFY_SERVER_IF(2, server_if);
+       VERIFY_HANDLE(3, attr_handle);
+       VERIFY_CONN_ID(4, conn_id);
+
+       /* confirm */
+       if (argc <= 5) {
+               haltest_error("No transport specified\n");
+               return;
+       }
+       confirm = atoi(argv[5]);
+
+       if (argc > 6) {
+               len = strlen(argv[6]);
+               scan_field(argv[6], len, (uint8_t *) data, sizeof(data));
+       }
+
+       EXEC(if_gatt->server->send_indication, server_if, attr_handle, conn_id,
+                                                       len, confirm, data);
+}
+
+/* send_response */
+
+static void gatts_send_response_p(int argc, const char *argv[])
+{
+       haltest_warn("%s is not implemented yet\n", __func__);
+}
+
+#define GATTS_METHODH(n, h) METHOD(#n, gatts_##n##_p, NULL, h)
+#define GATTS_METHODCH(n, h) METHOD(#n, gatts_##n##_p, gatts_##n##_c, h)
+
+static struct method server_methods[] = {
+       GATTS_METHODH(register_server, "[<uuid>]"),
+       GATTS_METHODCH(unregister_server, "<server_if>"),
+       GATTS_METHODCH(connect, "<server_if> <addr> [<is_direct>]"),
+       GATTS_METHODCH(disconnect, "<server_if> <addr> <conn_id>"),
+       GATTS_METHODCH(add_service, "<server_if> <srvc_id> <num_handles>"),
+       GATTS_METHODCH(add_included_service,
+                       "<server_if> <service_handle> <included_handle>"),
+       GATTS_METHODCH(add_characteristic,
+               "<server_if> <service_handle> <uuid> <properites> <permissions>"),
+       GATTS_METHODCH(add_descriptor, "<server_if> <uuid> <permissions>"),
+       GATTS_METHODCH(start_service,
+                               "<server_if> <service_handle> <transport>"),
+       GATTS_METHODCH(stop_service, "<server_if> <service_handle>"),
+       GATTS_METHODCH(delete_service, "<server_if> <service_handle>"),
+       GATTS_METHODH(send_indication,
+                       "<server_if> <attr_handle> <conn_id> <confirm> [<data>]"),
+       GATTS_METHODH(send_response, "<conn_id> <trans_id> <status>"),
+       END_METHOD
+};
+
+const struct interface gatt_server_if = {
+       .name = "gatts",
+       .methods = server_methods
+};
diff --git a/android/client/if-hf.c b/android/client/if-hf.c
new file mode 100644 (file)
index 0000000..d0e7a66
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2013 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 "if-main.h"
+#include "../hal-utils.h"
+
+const bthf_interface_t *if_hf = NULL;
+
+SINTMAP(bthf_at_response_t, -1, "(unknown)")
+       DELEMENT(BTHF_AT_RESPONSE_ERROR),
+       DELEMENT(BTHF_AT_RESPONSE_OK),
+ENDMAP
+
+SINTMAP(bthf_connection_state_t, -1, "(unknown)")
+       DELEMENT(BTHF_CONNECTION_STATE_DISCONNECTED),
+       DELEMENT(BTHF_CONNECTION_STATE_CONNECTING),
+       DELEMENT(BTHF_CONNECTION_STATE_CONNECTED),
+       DELEMENT(BTHF_CONNECTION_STATE_SLC_CONNECTED),
+       DELEMENT(BTHF_CONNECTION_STATE_DISCONNECTING),
+ENDMAP
+
+SINTMAP(bthf_audio_state_t, -1, "(unknown)")
+       DELEMENT(BTHF_AUDIO_STATE_DISCONNECTED),
+       DELEMENT(BTHF_AUDIO_STATE_CONNECTING),
+       DELEMENT(BTHF_AUDIO_STATE_CONNECTED),
+       DELEMENT(BTHF_AUDIO_STATE_DISCONNECTING),
+ENDMAP
+
+SINTMAP(bthf_vr_state_t, -1, "(unknown)")
+       DELEMENT(BTHF_VR_STATE_STOPPED),
+       DELEMENT(BTHF_VR_STATE_STARTED),
+ENDMAP
+
+SINTMAP(bthf_volume_type_t, -1, "(unknown)")
+       DELEMENT(BTHF_VOLUME_TYPE_SPK),
+       DELEMENT(BTHF_VOLUME_TYPE_MIC),
+ENDMAP
+
+SINTMAP(bthf_nrec_t, -1, "(unknown)")
+       DELEMENT(BTHF_NREC_STOP),
+       DELEMENT(BTHF_NREC_START),
+ENDMAP
+
+SINTMAP(bthf_chld_type_t, -1, "(unknown)")
+       DELEMENT(BTHF_CHLD_TYPE_RELEASEHELD),
+       DELEMENT(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD),
+       DELEMENT(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD),
+       DELEMENT(BTHF_CHLD_TYPE_ADDHELDTOCONF),
+ENDMAP
+
+/* Network Status */
+SINTMAP(bthf_network_state_t, -1, "(unknown)")
+       DELEMENT(BTHF_NETWORK_STATE_NOT_AVAILABLE),
+       DELEMENT(BTHF_NETWORK_STATE_AVAILABLE),
+ENDMAP
+
+/* Service type */
+SINTMAP(bthf_service_type_t, -1, "(unknown)")
+       DELEMENT(BTHF_SERVICE_TYPE_HOME),
+       DELEMENT(BTHF_SERVICE_TYPE_ROAMING),
+ENDMAP
+
+SINTMAP(bthf_call_state_t, -1, "(unknown)")
+       DELEMENT(BTHF_CALL_STATE_ACTIVE),
+       DELEMENT(BTHF_CALL_STATE_HELD),
+       DELEMENT(BTHF_CALL_STATE_DIALING),
+       DELEMENT(BTHF_CALL_STATE_ALERTING),
+       DELEMENT(BTHF_CALL_STATE_INCOMING),
+       DELEMENT(BTHF_CALL_STATE_WAITING),
+       DELEMENT(BTHF_CALL_STATE_IDLE),
+ENDMAP
+
+SINTMAP(bthf_call_direction_t, -1, "(unknown)")
+       DELEMENT(BTHF_CALL_DIRECTION_OUTGOING),
+       DELEMENT(BTHF_CALL_DIRECTION_INCOMING),
+ENDMAP
+
+SINTMAP(bthf_call_mode_t, -1, "(unknown)")
+       DELEMENT(BTHF_CALL_TYPE_VOICE),
+       DELEMENT(BTHF_CALL_TYPE_DATA),
+       DELEMENT(BTHF_CALL_TYPE_FAX),
+ENDMAP
+
+SINTMAP(bthf_call_mpty_type_t, -1, "(unknown)")
+       DELEMENT(BTHF_CALL_MPTY_TYPE_SINGLE),
+       DELEMENT(BTHF_CALL_MPTY_TYPE_MULTI),
+ENDMAP
+
+SINTMAP(bthf_call_addrtype_t, -1, "(unknown)")
+       DELEMENT(BTHF_CALL_ADDRTYPE_UNKNOWN),
+       DELEMENT(BTHF_CALL_ADDRTYPE_INTERNATIONAL),
+ENDMAP
+
+/* Callbacks */
+
+static char last_addr[MAX_ADDR_STR_LEN];
+
+/*
+ * Callback for connection state change.
+ * state will have one of the values from BtHfConnectionState
+ */
+static void connection_state_cb(bthf_connection_state_t state,
+                                                       bt_bdaddr_t *bd_addr)
+{
+       haltest_info("%s: state=%s bd_addr=%s\n", __func__,
+                                       bthf_connection_state_t2str(state),
+                                       bt_bdaddr_t2str(bd_addr, last_addr));
+}
+
+/*
+ * Callback for audio connection state change.
+ * state will have one of the values from BtHfAudioState
+ */
+static void audio_state_cb(bthf_audio_state_t state, bt_bdaddr_t *bd_addr)
+{
+       haltest_info("%s: state=%s bd_addr=%s\n", __func__,
+                                       bthf_audio_state_t2str(state),
+                                       bt_bdaddr_t2str(bd_addr, last_addr));
+}
+
+/*
+ * Callback for VR connection state change.
+ * state will have one of the values from BtHfVRState
+ */
+static void vr_cmd_cb(bthf_vr_state_t state)
+{
+       haltest_info("%s: state=%s\n", __func__, bthf_vr_state_t2str(state));
+}
+
+/* Callback for answer incoming call (ATA) */
+static void answer_call_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/* Callback for disconnect call (AT+CHUP) */
+static void hangup_call_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/*
+ * Callback for disconnect call (AT+CHUP)
+ * type will denote Speaker/Mic gain (BtHfVolumeControl).
+ */
+static void volume_cmd_cb(bthf_volume_type_t type, int volume)
+{
+       haltest_info("%s: type=%s volume=%d\n", __func__,
+                                       bthf_volume_type_t2str(type), volume);
+}
+
+/*
+ * Callback for dialing an outgoing call
+ * If number is NULL, redial
+ */
+static void dial_call_cmd_cb(char *number)
+{
+       haltest_info("%s: number=%s\n", __func__, number);
+}
+
+/*
+ * Callback for sending DTMF tones
+ * tone contains the dtmf character to be sent
+ */
+static void dtmf_cmd_cb(char tone)
+{
+       haltest_info("%s: tone=%d\n", __func__, tone);
+}
+
+/*
+ * Callback for enabling/disabling noise reduction/echo cancellation
+ * value will be 1 to enable, 0 to disable
+ */
+static void nrec_cmd_cb(bthf_nrec_t nrec)
+{
+       haltest_info("%s: nrec=%s\n", __func__, bthf_nrec_t2str(nrec));
+}
+
+/*
+ * Callback for call hold handling (AT+CHLD)
+ * value will contain the call hold command (0, 1, 2, 3)
+ */
+static void chld_cmd_cb(bthf_chld_type_t chld)
+{
+       haltest_info("%s: chld=%s\n", __func__, bthf_chld_type_t2str(chld));
+}
+
+/* Callback for CNUM (subscriber number) */
+static void cnum_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/* Callback for indicators (CIND) */
+static void cind_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/* Callback for operator selection (COPS) */
+static void cops_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/* Callback for call list (AT+CLCC) */
+static void clcc_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+/*
+ * Callback for unknown AT command recd from HF
+ * at_string will contain the unparsed AT string
+ */
+static void unknown_at_cmd_cb(char *at_string)
+{
+       haltest_info("%s: at_string=%s\n", __func__, at_string);
+}
+
+/* Callback for keypressed (HSP) event. */
+static void key_pressed_cmd_cb(void)
+{
+       haltest_info("%s\n", __func__);
+}
+
+static bthf_callbacks_t hf_cbacks = {
+
+       .size = sizeof(hf_cbacks),
+       .connection_state_cb = connection_state_cb,
+       .audio_state_cb = audio_state_cb,
+       .vr_cmd_cb = vr_cmd_cb,
+       .answer_call_cmd_cb = answer_call_cmd_cb,
+       .hangup_call_cmd_cb = hangup_call_cmd_cb,
+       .volume_cmd_cb = volume_cmd_cb,
+       .dial_call_cmd_cb = dial_call_cmd_cb,
+       .dtmf_cmd_cb = dtmf_cmd_cb,
+       .nrec_cmd_cb = nrec_cmd_cb,
+       .chld_cmd_cb = chld_cmd_cb,
+       .cnum_cmd_cb = cnum_cmd_cb,
+       .cind_cmd_cb = cind_cmd_cb,
+       .cops_cmd_cb = cops_cmd_cb,
+       .clcc_cmd_cb = clcc_cmd_cb,
+       .unknown_at_cmd_cb = unknown_at_cmd_cb,
+       .key_pressed_cmd_cb = key_pressed_cmd_cb,
+};
+
+/* init */
+
+static void init_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       EXEC(if_hf->init, &hf_cbacks);
+}
+
+/* connect */
+
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hf);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hf->connect, &addr);
+}
+
+/* disconnect */
+
+/*
+ * This completion function will be used for several methods
+ * returning recently connected address
+ */
+static void connected_addr_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = last_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+/* Map completion to connected_addr_c */
+#define disconnect_c connected_addr_c
+
+static void disconnect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hf);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hf->disconnect, &addr);
+}
+
+/* create an audio connection */
+
+/* Map completion to connected_addr_c */
+#define connect_audio_c connected_addr_c
+
+static void connect_audio_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hf);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hf->connect_audio, &addr);
+}
+
+/* close the audio connection */
+
+/* Map completion to connected_addr_c */
+#define disconnect_audio_c connected_addr_c
+
+static void disconnect_audio_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hf);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hf->disconnect_audio, &addr);
+}
+
+/* start voice recognition */
+
+static void start_voice_recognition_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       EXEC(if_hf->start_voice_recognition);
+}
+
+/* stop voice recognition */
+
+static void stop_voice_recognition_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       EXEC(if_hf->stop_voice_recognition);
+}
+
+/* volume control */
+
+static void volume_control_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(bthf_volume_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void volume_control_p(int argc, const char **argv)
+{
+       bthf_volume_type_t type;
+       int volume;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* volume type */
+       if (argc <= 2) {
+               haltest_error("No volume type specified\n");
+               return;
+       }
+       type = str2bthf_volume_type_t(argv[2]);
+
+       /* volume */
+       if (argc <= 3) {
+               haltest_error("No volume specified\n");
+               return;
+       }
+       volume = atoi(argv[3]);
+
+       EXEC(if_hf->volume_control, type, volume);
+}
+
+/* Combined device status change notification */
+
+static void device_status_notification_c(int argc, const char **argv,
+                                                       enum_func *enum_func,
+                                                       void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(bthf_network_state_t);
+               *enum_func = enum_defines;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(bthf_service_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void device_status_notification_p(int argc, const char **argv)
+{
+       bthf_network_state_t ntk_state;
+       bthf_service_type_t svc_type;
+       int signal;
+       int batt_chg;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* network state */
+       if (argc <= 2) {
+               haltest_error("No network state specified\n");
+               return;
+       }
+       ntk_state = str2bthf_network_state_t(argv[2]);
+
+       /* service type */
+       if (argc <= 3) {
+               haltest_error("No service type specified\n");
+               return;
+       }
+       svc_type = str2bthf_service_type_t(argv[3]);
+
+       /* signal */
+       if (argc <= 4) {
+               haltest_error("No signal specified\n");
+               return;
+       }
+       signal = atoi(argv[4]);
+
+       /* batt_chg */
+       if (argc <= 5) {
+               haltest_error("No batt_chg specified\n");
+               return;
+       }
+       batt_chg = atoi(argv[5]);
+
+       EXEC(if_hf->device_status_notification, ntk_state, svc_type, signal,
+                                                               batt_chg);
+}
+
+/* Response for COPS command */
+
+static void cops_response_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       /* response */
+       if (argc <= 2) {
+               haltest_error("No cops specified\n");
+               return;
+       }
+
+       EXEC(if_hf->cops_response, argv[2]);
+}
+
+/* Response for CIND command */
+
+static void cind_response_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 6) {
+               *user = TYPE_ENUM(bthf_call_state_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void cind_response_p(int argc, const char **argv)
+{
+       int svc;
+       int num_active;
+       int num_held;
+       bthf_call_state_t call_setup_state;
+       int signal;
+       int roam;
+       int batt_chg;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* svc */
+       if (argc <= 2) {
+               haltest_error("No service specified\n");
+               return;
+       }
+       svc = atoi(argv[2]);
+
+       /* num active */
+       if (argc <= 3) {
+               haltest_error("No num active specified\n");
+               return;
+       }
+       num_active = atoi(argv[3]);
+
+       /* num held */
+       if (argc <= 4) {
+               haltest_error("No num held specified\n");
+               return;
+       }
+       num_held = atoi(argv[4]);
+
+       /* call setup state */
+       if (argc <= 5) {
+               haltest_error("No call setup state specified\n");
+               return;
+       }
+       call_setup_state = str2bthf_call_state_t(argv[5]);
+
+       /* signal */
+       if (argc <= 6) {
+               haltest_error("No signal specified\n");
+               return;
+       }
+       signal = atoi(argv[6]);
+
+       /* roam */
+       if (argc <= 7) {
+               haltest_error("No roam specified\n");
+               return;
+       }
+       roam = atoi(argv[7]);
+
+       /* batt_chg */
+       if (argc <= 8) {
+               haltest_error("No batt_chg specified\n");
+               return;
+       }
+       batt_chg = atoi(argv[8]);
+
+       EXEC(if_hf->cind_response, svc, num_active, num_held, call_setup_state,
+                                                       signal, roam, batt_chg);
+}
+
+/* Pre-formatted AT response, typically in response to unknown AT cmd */
+
+static void formatted_at_response_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       /* response */
+       if (argc <= 2) {
+               haltest_error("No response specified\n");
+               return;
+       }
+
+       EXEC(if_hf->formatted_at_response, argv[2]);
+}
+
+/* at_response */
+
+static void at_response_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(bthf_at_response_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void at_response_p(int argc, const char **argv)
+{
+       bthf_at_response_t response_code;
+       int error_code = 0;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* response type */
+       if (argc <= 2) {
+               haltest_error("No response specified\n");
+               return;
+       }
+       response_code = str2bthf_at_response_t(argv[2]);
+
+       /* error code */
+       if (argc >= 3)
+               error_code = atoi(argv[3]);
+
+       EXEC(if_hf->at_response, response_code, error_code);
+}
+
+/* response for CLCC command */
+
+static void clcc_response_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 4) {
+               *user = TYPE_ENUM(bthf_call_direction_t);
+               *enum_func = enum_defines;
+       } else if (argc == 5) {
+               *user = TYPE_ENUM(bthf_call_state_t);
+               *enum_func = enum_defines;
+       } else if (argc == 6) {
+               *user = TYPE_ENUM(bthf_call_mode_t);
+               *enum_func = enum_defines;
+       } else if (argc == 7) {
+               *user = TYPE_ENUM(bthf_call_mpty_type_t);
+               *enum_func = enum_defines;
+       } else if (argc == 9) {
+               *user = TYPE_ENUM(bthf_call_addrtype_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void clcc_response_p(int argc, const char **argv)
+{
+       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;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* index */
+       if (argc <= 2) {
+               haltest_error("No index specified\n");
+               return;
+       }
+       index = atoi(argv[2]);
+
+       /* direction */
+       if (argc <= 3) {
+               haltest_error("No direction specified\n");
+               return;
+       }
+       dir = str2bthf_call_direction_t(argv[3]);
+
+       /* call state */
+       if (argc <= 4) {
+               haltest_error("No call state specified\n");
+               return;
+       }
+       state = str2bthf_call_state_t(argv[4]);
+
+       /* call mode */
+       if (argc <= 5) {
+               haltest_error("No mode specified\n");
+               return;
+       }
+       mode = str2bthf_call_mode_t(argv[5]);
+
+       /* call mpty type */
+       if (argc <= 6) {
+               haltest_error("No mpty type specified\n");
+               return;
+       }
+       mpty = str2bthf_call_mpty_type_t(argv[6]);
+
+       /* number */
+       if (argc <= 7) {
+               haltest_error("No number specified\n");
+               return;
+       }
+       number = argv[7];
+
+       /* call mpty type */
+       if (argc <= 8) {
+               haltest_error("No address type specified\n");
+               return;
+       }
+       type = str2bthf_call_addrtype_t(argv[8]);
+
+       EXEC(if_hf->clcc_response, index, dir, state, mode, mpty, number,
+                                                                       type);
+}
+
+/* phone state change */
+
+static void phone_state_change_c(int argc, const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 5) {
+               *user = TYPE_ENUM(bthf_call_state_t);
+               *enum_func = enum_defines;
+       } else if (argc == 7) {
+               *user = TYPE_ENUM(bthf_call_addrtype_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void phone_state_change_p(int argc, const char **argv)
+{
+       int num_active;
+       int num_held;
+       bthf_call_state_t call_setup_state;
+       const char *number;
+       bthf_call_addrtype_t type;
+
+       RETURN_IF_NULL(if_hf);
+
+       /* num_active */
+       if (argc <= 2) {
+               haltest_error("No num_active specified\n");
+               return;
+       }
+       num_active = atoi(argv[2]);
+
+       /* num_held */
+       if (argc <= 3) {
+               haltest_error("No num_held specified\n");
+               return;
+       }
+       num_held = atoi(argv[3]);
+
+       /* setup state */
+       if (argc <= 4) {
+               haltest_error("No call setup state specified\n");
+               return;
+       }
+       call_setup_state = str2bthf_call_state_t(argv[4]);
+
+       /* number */
+       if (argc <= 5) {
+               haltest_error("No number specified\n");
+               return;
+       }
+       number = argv[5];
+
+       /* call mpty type */
+       if (argc <= 6) {
+               haltest_error("No address type specified\n");
+               return;
+       }
+       type = str2bthf_call_addrtype_t(argv[6]);
+
+       EXEC(if_hf->phone_state_change, num_active, num_held, call_setup_state,
+                                                               number, type);
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hf);
+
+       EXECV(if_hf->cleanup);
+       if_hf = NULL;
+}
+
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHODCH(connect, "<addr>"),
+       STD_METHODCH(disconnect, "<addr>"),
+       STD_METHODCH(connect_audio, "<addr>"),
+       STD_METHODCH(disconnect_audio, "<addr>"),
+       STD_METHOD(start_voice_recognition),
+       STD_METHOD(stop_voice_recognition),
+       STD_METHODCH(volume_control, "<vol_type> <volume>"),
+       STD_METHODCH(device_status_notification,
+                       "<ntk_state> <svt_type> <signal> <batt_chg>"),
+       STD_METHODH(cops_response, "<cops string>"),
+       STD_METHODCH(cind_response,
+                       "<svc> <num_active> <num_held> <setup_state> <signal> <roam> <batt_chg>"),
+       STD_METHODH(formatted_at_response, "<at_response>"),
+       STD_METHODCH(at_response, "<response_code> [<error_code>]"),
+       STD_METHODCH(clcc_response,
+                       "<index> <direction> <state> <mode> <mpty> <number> <type>"),
+       STD_METHODCH(phone_state_change,
+                       "<num_active> <num_held> <setup_state> <number> <type>"),
+       STD_METHOD(cleanup),
+       END_METHOD
+};
+
+const struct interface hf_if = {
+       .name = "handsfree",
+       .methods = methods
+};
diff --git a/android/client/if-hh.c b/android/client/if-hh.c
new file mode 100644 (file)
index 0000000..b8ebc8e
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <ctype.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+
+#include "if-main.h"
+#include "pollhandler.h"
+#include "../hal-utils.h"
+
+const bthh_interface_t *if_hh = NULL;
+
+SINTMAP(bthh_protocol_mode_t, -1, "(unknown)")
+       DELEMENT(BTHH_REPORT_MODE),
+       DELEMENT(BTHH_BOOT_MODE),
+       DELEMENT(BTHH_UNSUPPORTED_MODE),
+ENDMAP
+
+SINTMAP(bthh_report_type_t, -1, "(unknown)")
+       DELEMENT(BTHH_INPUT_REPORT),
+       DELEMENT(BTHH_OUTPUT_REPORT),
+       DELEMENT(BTHH_FEATURE_REPORT),
+ENDMAP
+
+SINTMAP(bthh_connection_state_t, -1, "(unknown)")
+       DELEMENT(BTHH_CONN_STATE_CONNECTED),
+       DELEMENT(BTHH_CONN_STATE_CONNECTING),
+       DELEMENT(BTHH_CONN_STATE_DISCONNECTED),
+       DELEMENT(BTHH_CONN_STATE_DISCONNECTING),
+       DELEMENT(BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST),
+       DELEMENT(BTHH_CONN_STATE_FAILED_KBD_FROM_HOST),
+       DELEMENT(BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES),
+       DELEMENT(BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER),
+       DELEMENT(BTHH_CONN_STATE_FAILED_GENERIC),
+       DELEMENT(BTHH_CONN_STATE_UNKNOWN),
+ENDMAP
+
+SINTMAP(bthh_status_t, -1, "(unknown)")
+       DELEMENT(BTHH_OK),
+       DELEMENT(BTHH_HS_HID_NOT_READY),
+       DELEMENT(BTHH_HS_INVALID_RPT_ID),
+       DELEMENT(BTHH_HS_TRANS_NOT_SPT),
+       DELEMENT(BTHH_HS_INVALID_PARAM),
+       DELEMENT(BTHH_HS_ERROR),
+       DELEMENT(BTHH_ERR),
+       DELEMENT(BTHH_ERR_SDP),
+       DELEMENT(BTHH_ERR_PROTO),
+       DELEMENT(BTHH_ERR_DB_FULL),
+       DELEMENT(BTHH_ERR_TOD_UNSPT),
+       DELEMENT(BTHH_ERR_NO_RES),
+       DELEMENT(BTHH_ERR_AUTH_FAILED),
+       DELEMENT(BTHH_ERR_HDL),
+ENDMAP
+
+static char connected_device_addr[MAX_ADDR_STR_LEN];
+/*
+ * Callback for connection state change.
+ * state will have one of the values from bthh_connection_state_t
+ */
+static void connection_state_cb(bt_bdaddr_t *bd_addr,
+                                               bthh_connection_state_t state)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: bd_addr=%s connection_state=%s\n", __func__,
+                                       bt_bdaddr_t2str(bd_addr, addr),
+                                       bthh_connection_state_t2str(state));
+       if (state == BTHH_CONN_STATE_CONNECTED)
+               strcpy(connected_device_addr, addr);
+}
+
+/*
+ * Callback for virtual unplug api.
+ * the status of the virtual unplug
+ */
+static void virtual_unplug_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: bd_addr=%s hh_status=%s\n", __func__,
+                                               bt_bdaddr_t2str(bd_addr, addr),
+                                               bthh_status_t2str(hh_status));
+}
+
+/*
+ * Callback for get hid info
+ * hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id,
+ * version, ctry_code, len
+ */
+static void hid_info_cb(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       /* TODO: bluedroid does not seem to ever call this callback */
+       haltest_info("%s: bd_addr=%s\n", __func__,
+                                               bt_bdaddr_t2str(bd_addr, addr));
+}
+
+/*
+ * Callback for get/set protocol api.
+ * the protocol mode is one of the value from bthh_protocol_mode_t
+ */
+static void protocol_mode_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
+                                               bthh_protocol_mode_t mode)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: bd_addr=%s hh_status=%s mode=%s\n", __func__,
+                                       bt_bdaddr_t2str(bd_addr, addr),
+                                       bthh_status_t2str(hh_status),
+                                       bthh_protocol_mode_t2str(mode));
+}
+
+/*
+ * Callback for get/set_idle_time api.
+ */
+static void idle_time_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
+                                                               int idle_rate)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       haltest_info("%s: bd_addr=%s hh_status=%s idle_rate=%d\n", __func__,
+                               bt_bdaddr_t2str(bd_addr, addr),
+                               bthh_status_t2str(hh_status), idle_rate);
+}
+
+
+/*
+ * Callback for get report api.
+ * if status is ok rpt_data contains the report data
+ */
+static void get_report_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
+                                               uint8_t *rpt_data, int rpt_size)
+{
+       char addr[MAX_ADDR_STR_LEN];
+
+       /* TODO: print actual report */
+       haltest_info("%s: bd_addr=%s hh_status=%s rpt_size=%d\n", __func__,
+                                       bt_bdaddr_t2str(bd_addr, addr),
+                                       bthh_status_t2str(hh_status), rpt_size);
+}
+
+static bthh_callbacks_t bthh_callbacks = {
+       .size = sizeof(bthh_callbacks),
+       .connection_state_cb = connection_state_cb,
+       .hid_info_cb = hid_info_cb,
+       .protocol_mode_cb = protocol_mode_cb,
+       .idle_time_cb = idle_time_cb,
+       .get_report_cb = get_report_cb,
+       .virtual_unplug_cb = virtual_unplug_cb
+};
+
+/* init */
+
+static void init_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hh);
+
+       EXEC(if_hh->init, &bthh_callbacks);
+}
+
+/* connect */
+
+static void connect_c(int argc, const const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = (void *) connected_device_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hh->connect, &addr);
+}
+
+/* disconnect */
+
+/* Same completion as connect_c */
+#define disconnect_c connect_c
+
+static void disconnect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hh->disconnect, &addr);
+}
+
+/* virtual_unplug */
+
+/* Same completion as connect_c */
+#define virtual_unplug_c connect_c
+
+static void virtual_unplug_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_hh->virtual_unplug, &addr);
+}
+
+/* set_info */
+
+static void set_info_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bthh_hid_info_t hid_info;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+       /* TODO: set_info does not seem to be called anywhere */
+
+       EXEC(if_hh->set_info, &addr, hid_info);
+}
+
+/* get_protocol */
+
+static void get_protocol_c(int argc, const const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = connected_device_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(bthh_protocol_mode_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void get_protocol_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bthh_protocol_mode_t protocolMode;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc < 4) {
+               haltest_error("No protocol mode specified\n");
+               return;
+       }
+       protocolMode = str2bthh_protocol_mode_t(argv[3]);
+
+       EXEC(if_hh->get_protocol, &addr, protocolMode);
+}
+
+/* set_protocol */
+
+/* Same completion as get_protocol_c */
+#define set_protocol_c get_protocol_c
+
+static void set_protocol_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bthh_protocol_mode_t protocolMode;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc < 4) {
+               haltest_error("No protocol mode specified\n");
+               return;
+       }
+       protocolMode = str2bthh_protocol_mode_t(argv[3]);
+
+       EXEC(if_hh->set_protocol, &addr, protocolMode);
+}
+
+/* get_report */
+
+static void get_report_c(int argc, const const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = connected_device_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(bthh_report_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void get_report_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bthh_report_type_t reportType;
+       uint8_t reportId;
+       int bufferSize;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc < 4) {
+               haltest_error("No report type specified\n");
+               return;
+       }
+       reportType = str2bthh_report_type_t(argv[3]);
+
+       if (argc < 5) {
+               haltest_error("No reportId specified\n");
+               return;
+       }
+       reportId = (uint8_t) atoi(argv[4]);
+
+       if (argc < 6) {
+               haltest_error("No bufferSize specified\n");
+               return;
+       }
+       bufferSize = atoi(argv[5]);
+
+       EXEC(if_hh->get_report, &addr, reportType, reportId, bufferSize);
+}
+
+/* set_report */
+
+static void set_report_c(int argc, const const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = connected_device_addr;
+               *enum_func = enum_one_string;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(bthh_report_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void set_report_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       bthh_report_type_t reportType;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc <= 3) {
+               haltest_error("No report type specified\n");
+               return;
+       }
+       reportType = str2bthh_report_type_t(argv[3]);
+
+       if (argc <= 4) {
+               haltest_error("No report specified\n");
+               return;
+       }
+
+       EXEC(if_hh->set_report, &addr, reportType, (char *) argv[4]);
+}
+
+/* send_data */
+
+static void send_data_c(int argc, const const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = connected_device_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void send_data_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_hh);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       if (argc <= 3) {
+               haltest_error("No data to send specified\n");
+               return;
+       }
+
+       EXEC(if_hh->send_data, &addr, (char *) argv[3]);
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_hh);
+
+       EXECV(if_hh->cleanup);
+}
+
+/* Methods available in bthh_interface_t */
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHODCH(connect, "<addr>"),
+       STD_METHODCH(disconnect, "<addr>"),
+       STD_METHODCH(virtual_unplug, "<addr>"),
+       STD_METHOD(set_info),
+       STD_METHODCH(get_protocol, "<addr> <mode>"),
+       STD_METHODCH(set_protocol, "<addr> <mode>"),
+       STD_METHODCH(get_report, "<addr> <type> <report_id> <size>"),
+       STD_METHODCH(set_report, "<addr> <type> <hex_encoded_report>"),
+       STD_METHODCH(send_data, "<addr> <hex_encoded_data>"),
+       STD_METHOD(cleanup),
+       END_METHOD
+};
+
+const struct interface hh_if = {
+       .name = "hidhost",
+       .methods = methods
+};
diff --git a/android/client/if-main.h b/android/client/if-main.h
new file mode 100644 (file)
index 0000000..a83f48b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <poll.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_sock.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_hl.h>
+
+#if PLATFORM_SDK_VERSION > 17
+#include <hardware/bt_rc.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_gatt_types.h>
+#include <hardware/bt_gatt_client.h>
+#include <hardware/bt_gatt_server.h>
+#endif
+
+/* Interfaces from hal that can be populated during application lifetime */
+extern const bt_interface_t *if_bluetooth;
+extern const btav_interface_t *if_av;
+extern const bthf_interface_t *if_hf;
+extern const bthh_interface_t *if_hh;
+extern const btpan_interface_t *if_pan;
+extern const btsock_interface_t *if_sock;
+#if PLATFORM_SDK_VERSION > 17
+extern const btgatt_interface_t *if_gatt;
+extern const btgatt_server_interface_t *if_gatt_server;
+extern const btgatt_client_interface_t *if_gatt_client;
+#endif
+
+/*
+ * Structure defines top level interfaces that can be used in test tool
+ * this will contain values as: bluetooth, av, gatt, socket, pan...
+ */
+struct interface {
+       const char *name; /* interface name */
+       struct method *methods; /* methods available for this interface */
+};
+
+extern const struct interface bluetooth_if;
+extern const struct interface av_if;
+#if PLATFORM_SDK_VERSION > 17
+extern const struct interface gatt_if;
+extern const struct interface gatt_client_if;
+extern const struct interface gatt_server_if;
+#endif
+extern const struct interface pan_if;
+extern const struct interface sock_if;
+extern const struct interface hf_if;
+extern const struct interface hh_if;
+
+/* Interfaces that will show up in tool (first part of command line) */
+extern const struct interface *interfaces[];
+
+#define METHOD(name, func, comp, help) {name, func, comp, help}
+#define STD_METHOD(m) {#m, m##_p, NULL, NULL}
+#define STD_METHODC(m) {#m, m##_p, m##_c, NULL}
+#define STD_METHODH(m, h) {#m, m##_p, NULL, h}
+#define STD_METHODCH(m, h) {#m, m##_p, m##_c, h}
+#define END_METHOD {"", NULL, NULL, NULL}
+
+/*
+ * Function to parse argument for function, argv[0] and argv[1] are already
+ * parsed before this function is called and contain interface and method name
+ * up to argc - 1 arguments are finished and should be used to decide which
+ * function enumeration function to return
+ */
+typedef void (*parse_and_call)(int argc, const char **argv);
+
+/*
+ * This is prototype of function that will return string for given number.
+ * Purpose is to enumerate string for auto completion.
+ * Function of this type will always be called in loop.
+ * First time function is called i = 0, then if function returns non-NULL
+ * it will be called again till for some value of i it will return NULL
+ */
+typedef const char *(*enum_func)(void *user, int i);
+
+/*
+ * This is prototype of function that when given argc, argv will
+ * fill enum_func with pointer to function that will enumerate
+ * parameters for argc argument, user will be passed to enum_func.
+ */
+typedef void (*tab_complete)(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user);
+
+/*
+ * For each method there is name and two functions to parse command line
+ * and call proper hal function on.
+ */
+struct method {
+       const char *name;
+       parse_and_call func;
+       tab_complete complete;
+       const char *help;
+};
+
+int haltest_error(const char *format, ...);
+int haltest_info(const char *format, ...);
+int haltest_warn(const char *format, ...);
+
+/*
+ * Enumerator for discovered devices, to be used as tab completion enum_func
+ */
+const char *enum_devices(void *v, int i);
+const char *interface_name(void *v, int i);
+const char *command_name(void *v, int i);
+void add_remote_device(const bt_bdaddr_t *addr);
+
+const struct interface *get_interface(const char *name);
+struct method *get_method(struct method *methods, const char *name);
+struct method *get_command(const char *name);
+const struct method *get_interface_method(const char *iname,
+                                                       const char *mname);
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+/* Helper macro for executing function on interface and printing BT_STATUS */
+#define EXEC(f, ...) \
+       { \
+               int err = f(__VA_ARGS__); \
+               haltest_info("%s: %s\n", #f, bt_status_t2str(err)); \
+       }
+
+/* Helper macro for executing void function on interface */
+#define EXECV(f, ...) \
+       { \
+               (void) f(__VA_ARGS__); \
+               haltest_info("%s: void\n", #f); \
+       }
+
+#define RETURN_IF_NULL(x) \
+       do { if (!x) { haltest_error("%s is NULL\n", #x); return; } } while (0)
+
+#define VERIFY_ADDR_ARG(n, adr) \
+       do { \
+               if (n < argc) {\
+                       str2bt_bdaddr_t(argv[n], adr); \
+               } else { \
+                       haltest_error("No address specified\n");\
+                       return;\
+               } \
+       } while (0)
diff --git a/android/client/if-pan.c b/android/client/if-pan.c
new file mode 100644 (file)
index 0000000..a11f2a3
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2013 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 <hardware/bluetooth.h>
+
+#include "if-main.h"
+#include "../hal-utils.h"
+
+const btpan_interface_t *if_pan = NULL;
+
+typedef int btpan_role_t;
+
+SINTMAP(btpan_role_t, -1, "(unknown)")
+       DELEMENT(BTPAN_ROLE_NONE),
+       DELEMENT(BTPAN_ROLE_PANNAP),
+       DELEMENT(BTPAN_ROLE_PANU),
+ENDMAP
+
+SINTMAP(btpan_connection_state_t, -1, "(unknown)")
+       DELEMENT(BTPAN_STATE_CONNECTED),
+       DELEMENT(BTPAN_STATE_CONNECTING),
+       DELEMENT(BTPAN_STATE_DISCONNECTED),
+       DELEMENT(BTPAN_STATE_DISCONNECTING),
+ENDMAP
+
+SINTMAP(btpan_control_state_t, -1, "(unknown)")
+       DELEMENT(BTPAN_STATE_ENABLED),
+       DELEMENT(BTPAN_STATE_DISABLED),
+ENDMAP
+
+static void control_state_cb(btpan_control_state_t state, bt_status_t error,
+                                       int local_role, const char *ifname)
+{
+       haltest_info("%s: state=%s error=%s local_role=%s ifname=%s\n",
+                       __func__, btpan_control_state_t2str(state),
+                       bt_status_t2str(error), btpan_role_t2str(local_role),
+                       ifname);
+}
+
+static char last_used_addr[MAX_ADDR_STR_LEN];
+
+static void connection_state_cb(btpan_connection_state_t state,
+                               bt_status_t error, const bt_bdaddr_t *bd_addr,
+                               int local_role, int remote_role)
+{
+       haltest_info("%s: state=%s error=%s bd_addr=%s local_role=%s remote_role=%s\n",
+                       __func__, btpan_connection_state_t2str(state),
+                       bt_status_t2str(error),
+                       bt_bdaddr_t2str(bd_addr, last_used_addr),
+                       btpan_role_t2str(local_role),
+                       btpan_role_t2str(remote_role));
+}
+
+static btpan_callbacks_t pan_cbacks = {
+       .size = sizeof(pan_cbacks),
+       .control_state_cb = control_state_cb,
+       .connection_state_cb = connection_state_cb
+};
+
+static void init_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_pan);
+
+       EXEC(if_pan->init, &pan_cbacks);
+}
+
+/* enable */
+
+static void enable_c(int argc, const const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(btpan_role_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void enable_p(int argc, const char **argv)
+{
+       int local_role;
+
+       RETURN_IF_NULL(if_pan);
+
+       /* local role */
+       if (argc < 3) {
+               haltest_error("No local mode specified\n");
+               return;
+       }
+       local_role = str2btpan_role_t(argv[2]);
+       if (local_role == -1)
+               local_role = atoi(argv[2]);
+
+       EXEC(if_pan->enable, local_role);
+}
+
+/* get_local_role */
+
+static void get_local_role_p(int argc, const char **argv)
+{
+       int local_role;
+
+       RETURN_IF_NULL(if_pan);
+
+       local_role = if_pan->get_local_role();
+       haltest_info("local_role: %s\n", btpan_role_t2str(local_role));
+}
+
+/* connect */
+
+static void connect_c(int argc, const const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       } else if (argc == 4 || argc == 5) {
+               *user = TYPE_ENUM(btpan_role_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       int local_role;
+       int remote_role;
+
+       RETURN_IF_NULL(if_pan);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       /* local role */
+       if (argc < 4) {
+               haltest_error("No local mode specified\n");
+               return;
+       }
+       local_role = str2btpan_role_t(argv[3]);
+       if (local_role == -1)
+               local_role = atoi(argv[3]);
+
+       /* remote role */
+       if (argc < 5) {
+               haltest_error("No remote mode specified\n");
+               return;
+       }
+       remote_role = str2btpan_role_t(argv[4]);
+       if (remote_role == -1)
+               remote_role = atoi(argv[4]);
+
+       EXEC(if_pan->connect, &addr, local_role, remote_role);
+}
+
+/* disconnect */
+
+static void disconnect_c(int argc, const const char **argv,
+                                       enum_func *enum_func, void **user)
+{
+       if (argc == 3) {
+               *user = last_used_addr;
+               *enum_func = enum_one_string;
+       }
+}
+
+static void disconnect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+
+       RETURN_IF_NULL(if_pan);
+       VERIFY_ADDR_ARG(2, &addr);
+
+       EXEC(if_pan->disconnect, &addr);
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+       RETURN_IF_NULL(if_pan);
+
+       EXECV(if_pan->cleanup);
+       if_pan = NULL;
+}
+
+static struct method methods[] = {
+       STD_METHOD(init),
+       STD_METHODCH(connect, "<addr> <local_role> <remote_role>"),
+       STD_METHODCH(enable, "<local_role>"),
+       STD_METHOD(get_local_role),
+       STD_METHODCH(disconnect, "<addr>"),
+       STD_METHOD(cleanup),
+       END_METHOD
+};
+
+const struct interface pan_if = {
+       .name = "pan",
+       .methods = methods
+};
diff --git a/android/client/if-sock.c b/android/client/if-sock.c
new file mode 100644 (file)
index 0000000..2cd06e8
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "if-main.h"
+#include "pollhandler.h"
+#include "../hal-utils.h"
+
+const btsock_interface_t *if_sock = NULL;
+
+SINTMAP(btsock_type_t, -1, "(unknown)")
+       DELEMENT(BTSOCK_RFCOMM),
+       DELEMENT(BTSOCK_SCO),
+       DELEMENT(BTSOCK_L2CAP),
+ENDMAP
+
+#define MAX_LISTEN_FD 15
+static int listen_fd[MAX_LISTEN_FD];
+static int listen_fd_count;
+
+/*
+ * This function reads data from file descriptor and
+ * prints it to the user
+ */
+static void receive_from_client(struct pollfd *pollfd)
+{
+       char buf[16];
+       /* Buffer for lines:
+        * 41 42 43 20 20 00 31 32 00 07 04 00 00 00 00 00 ABC  .12.....
+        */
+       char outbuf[sizeof(buf) * 4 + 2];
+       int i;
+       int ret;
+
+       if (pollfd->revents & POLLHUP) {
+               haltest_error("Disconnected fd=%d\n", pollfd->fd);
+               poll_unregister_fd(pollfd->fd, receive_from_client);
+       } else if (pollfd->revents & POLLIN) {
+               haltest_info("receiving from client fd=%d\n", pollfd->fd);
+
+               do {
+                       memset(outbuf, ' ', sizeof(outbuf));
+                       outbuf[sizeof(outbuf) - 1] = 0;
+                       ret = recv(pollfd->fd, buf, sizeof(buf), MSG_DONTWAIT);
+
+                       for (i = 0; i < ret; ++i)
+                               sprintf(outbuf + i * 3, "%02X ",
+                                                       (unsigned) buf[i]);
+                       outbuf[i * 3] = ' ';
+                       for (i = 0; i < ret; ++i)
+                               sprintf(outbuf + 48 + i, "%c",
+                                       (isprint(buf[i]) ? buf[i] : '.'));
+                       if (ret > 0)
+                               haltest_info("%s\n", outbuf);
+               } while (ret > 0);
+       } else {
+               /* For now disconnect on all other events */
+               haltest_error("Poll event %x\n", pollfd->revents);
+               poll_unregister_fd(pollfd->fd, receive_from_client);
+       }
+}
+
+/*
+ * This function read from fd socket information about
+ * connected socket
+ */
+static void receive_sock_connect_signal(struct pollfd *pollfd)
+{
+       sock_connect_signal_t cs;
+       char addr_str[MAX_ADDR_STR_LEN];
+
+       if (pollfd->revents & POLLIN) {
+               int ret;
+
+               poll_unregister_fd(pollfd->fd, receive_sock_connect_signal);
+               ret = read(pollfd->fd, &cs, sizeof(cs));
+               if (ret != sizeof(cs)) {
+                       haltest_info("Read on connect return %d\n", ret);
+                       return;
+               }
+
+               haltest_info("Connection to %s channel %d status=%d\n",
+                               bt_bdaddr_t2str(&cs.bd_addr, addr_str),
+                               cs.channel, cs.status);
+
+               if (cs.status == 0)
+                       poll_register_fd(pollfd->fd, POLLIN,
+                                                       receive_from_client);
+       }
+
+       if (pollfd->revents & POLLHUP) {
+               haltest_error("Disconnected fd=%d revents=0x%X\n", pollfd->fd,
+                               pollfd->revents);
+               poll_unregister_fd(pollfd->fd, receive_sock_connect_signal);
+       }
+}
+
+/*
+ * This function read from fd socket information about
+ * incoming connection and starts monitoring new connection
+ * on file descriptor read from fd.
+ */
+static void read_accepted(int fd)
+{
+       int ret;
+       struct msghdr msg;
+       struct iovec iv;
+       char cmsgbuf[CMSG_SPACE(1)];
+       struct cmsghdr *cmsgptr;
+       sock_connect_signal_t cs;
+       int accepted_fd = -1;
+       char addr_str[MAX_ADDR_STR_LEN];
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&iv, 0, sizeof(iv));
+
+       iv.iov_base = &cs;
+       iv.iov_len = sizeof(cs);
+
+       msg.msg_iov = &iv;
+       msg.msg_iovlen = 1;
+       msg.msg_control = cmsgbuf;
+       msg.msg_controllen = sizeof(cmsgbuf);
+
+       do {
+               ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
+       } while (ret < 0 && errno == EINTR);
+
+       if (ret < 16 ||
+               (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0)
+               haltest_error("Failed to accept connection\n");
+
+       for (cmsgptr = CMSG_FIRSTHDR(&msg);
+               cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
+               int *descs;
+               int count;
+
+               if (cmsgptr->cmsg_level != SOL_SOCKET ||
+                       cmsgptr->cmsg_type != SCM_RIGHTS)
+                       continue;
+
+               descs = (int *) CMSG_DATA(cmsgptr);
+               count = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+
+               if (count != 1)
+                       haltest_error("Failed to accept descriptors count=%d\n",
+                                                                       count);
+
+               accepted_fd = descs[0];
+               break;
+       }
+
+       haltest_info("Incoming connection from %s channel %d status=%d fd=%d\n",
+                                       bt_bdaddr_t2str(&cs.bd_addr, addr_str),
+                                       cs.channel, cs.status, accepted_fd);
+       poll_register_fd(accepted_fd, POLLIN, receive_from_client);
+}
+
+/* handles incoming connections on socket */
+static void client_connected(struct pollfd *pollfd)
+{
+       haltest_info("client connected %x\n", pollfd->revents);
+
+       if (pollfd->revents & POLLHUP)
+               poll_unregister_fd(pollfd->fd, client_connected);
+       else if (pollfd->revents & POLLIN)
+               read_accepted(pollfd->fd);
+}
+
+/** listen */
+
+static void listen_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *user = TYPE_ENUM(btsock_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void listen_p(int argc, const char **argv)
+{
+       btsock_type_t type;
+       const char *service_name;
+       bt_uuid_t service_uuid;
+       int channel;
+       int sock_fd;
+       int flags;
+
+       RETURN_IF_NULL(if_sock);
+
+       /* Socket type */
+       if (argc < 3) {
+               haltest_error("No socket type specified\n");
+               return;
+       }
+       type = str2btsock_type_t(argv[2]);
+       if ((int) type == -1)
+               type = atoi(argv[2]);
+
+       /* service name */
+       if (argc < 4) {
+               haltest_error("No service name specified\n");
+               return;
+       }
+       service_name = argv[3];
+
+       /* uuid */
+       if (argc < 5) {
+               haltest_error("No uuid specified\n");
+               return;
+       }
+       str2bt_uuid_t(argv[4], &service_uuid);
+
+       /* channel */
+       channel = argc > 5 ? atoi(argv[5]) : 0;
+
+       /* flags */
+       flags = argc > 6 ? atoi(argv[6]) : 0;
+
+       if (listen_fd_count >= MAX_LISTEN_FD) {
+               haltest_error("Max (%d) listening sockets exceeded\n",
+                                                       listen_fd_count);
+               return;
+       }
+       EXEC(if_sock->listen, type, service_name,
+                               &service_uuid.uu[0], channel, &sock_fd, flags);
+       if (sock_fd > 0) {
+               int channel = 0;
+               int ret = read(sock_fd, &channel, 4);
+               if (ret != 4)
+                       haltest_info("Read channel failed\n");
+               haltest_info("Channel returned from first read %d\n", channel);
+               listen_fd[listen_fd_count++] = sock_fd;
+               poll_register_fd(sock_fd, POLLIN, client_connected);
+       }
+}
+
+/** connect */
+
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+                                                               void **user)
+{
+       if (argc == 3) {
+               *enum_func = enum_devices;
+       } else if (argc == 4) {
+               *user = TYPE_ENUM(btsock_type_t);
+               *enum_func = enum_defines;
+       }
+}
+
+static void connect_p(int argc, const char **argv)
+{
+       bt_bdaddr_t addr;
+       btsock_type_t type;
+       bt_uuid_t uuid;
+       int channel;
+       int sock_fd;
+       int flags;
+
+       /* Address */
+       if (argc <= 2) {
+               haltest_error("No address specified\n");
+               return;
+       }
+       str2bt_bdaddr_t(argv[2], &addr);
+
+       /* Socket type */
+       if (argc <= 3) {
+               haltest_error("No socket type specified\n");
+               return;
+       }
+       type = str2btsock_type_t(argv[3]);
+       if ((int) type == -1)
+               type = atoi(argv[3]);
+
+       /* uuid */
+       if (argc <= 4) {
+               haltest_error("No uuid specified\n");
+               return;
+       }
+       str2bt_uuid_t(argv[4], &uuid);
+
+       /* channel */
+       if (argc <= 5) {
+               haltest_error("No channel specified\n");
+               return;
+       }
+       channel = atoi(argv[5]);
+
+       /* flags */
+       flags = argc <= 6 ? 0 : atoi(argv[6]);
+
+       RETURN_IF_NULL(if_sock);
+
+       EXEC(if_sock->connect, &addr, type, &uuid.uu[0], channel, &sock_fd,
+                                                                       flags);
+       if (sock_fd > 0) {
+               int channel = 0;
+               int ret = read(sock_fd, &channel, 4);
+
+               if (ret != 4)
+                       haltest_info("Read channel failed\n");
+               haltest_info("Channel returned from first read %d\n", channel);
+               listen_fd[listen_fd_count++] = sock_fd;
+               poll_register_fd(sock_fd, POLLIN, receive_sock_connect_signal);
+       }
+}
+
+/* Methods available in btsock_interface_t */
+static struct method methods[] = {
+       STD_METHODCH(listen,
+                       "<sock_type> <srvc_name> <uuid> [<channle>] [<flags>]"),
+       STD_METHODCH(connect,
+                       "<addr> <sock_type> <uuid> <channle> [<flags>]"),
+       END_METHOD
+};
+
+const struct interface sock_if = {
+       .name = "socket",
+       .methods = methods
+};
diff --git a/android/client/pollhandler.c b/android/client/pollhandler.c
new file mode 100644 (file)
index 0000000..6160921
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "pollhandler.h"
+
+/*
+ * Code that allows to poll multiply file descriptors for events
+ * File descriptors can be added and removed at runtime
+ *
+ * Call poll_register_fd function first to add file descriptors to monitor
+ * Then call poll_dispatch_loop that will poll all registered file descriptors
+ * as long as they are not unregistered.
+ *
+ * When event happen on given fd appropriate user supplied handler is called
+ */
+
+/* Maximum number of files to monitor */
+#define MAX_OPEN_FD 10
+
+/* Storage for pollfd structures for monitored file descriptors */
+static struct pollfd fds[MAX_OPEN_FD];
+static poll_handler fds_handler[MAX_OPEN_FD];
+/* Number of registered file descriptors */
+static int fds_count = 0;
+
+/*
+ * Function polls file descriptor in loop and calls appropriate handler
+ * on event. Function returns when there is no more file descriptor to
+ * monitor
+ */
+void poll_dispatch_loop(void)
+{
+       while (fds_count > 0) {
+               int i;
+               int cur_fds_count = fds_count;
+               int ready = poll(fds, fds_count, 1000);
+
+               for (i = 0; i < fds_count && ready > 0; ++i) {
+                       if (fds[i].revents == 0)
+                               continue;
+
+                       fds_handler[i](fds + i);
+                       ready--;
+                       /*
+                        * If handler was remove from table
+                        * just skip the rest and poll again
+                        * This is due to reordering of tables in
+                        * register/unregister functions
+                        */
+                       if (cur_fds_count != fds_count)
+                               break;
+               }
+       }
+}
+
+/*
+ * Registers file descriptor to be monitored for events (see man poll(2))
+ * for events.
+ *
+ * return non negative value on success
+ * -EMFILE when there are to much descriptors
+ */
+int poll_register_fd(int fd, short events, poll_handler ph)
+{
+       if (fds_count >= MAX_OPEN_FD)
+               return -EMFILE;
+
+       fds_handler[fds_count] = ph;
+       fds[fds_count].fd = fd;
+       fds[fds_count].events = events;
+       fds_count++;
+
+       return fds_count;
+}
+
+/*
+ * Unregisters file descriptor
+ * Both fd and ph must match previously registered data
+ *
+ * return 0 if unregister succeeded
+ * -EBADF if arguments do not match any register handler
+ */
+int poll_unregister_fd(int fd, poll_handler ph)
+{
+       int i;
+
+       for (i = 0; i < fds_count; ++i) {
+               if (fds_handler[i] == ph && fds[i].fd == fd) {
+                       fds_count--;
+                       if (i < fds_count) {
+                               fds[i].fd = fds[fds_count].fd;
+                               fds[i].events = fds[fds_count].events;
+                               fds_handler[i] = fds_handler[fds_count];
+                       }
+                       return 0;
+               }
+       }
+       return -EBADF;
+}
diff --git a/android/client/pollhandler.h b/android/client/pollhandler.h
new file mode 100644 (file)
index 0000000..e2f22df
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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 <poll.h>
+
+/* Function to be called when there are event for some descriptor */
+typedef void (*poll_handler)(struct pollfd *pollfd);
+
+int poll_register_fd(int fd, short events, poll_handler ph);
+int poll_unregister_fd(int fd, poll_handler ph);
+
+void poll_dispatch_loop(void);
diff --git a/android/client/tabcompletion.c b/android/client/tabcompletion.c
new file mode 100644 (file)
index 0000000..f965620
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <ctype.h>
+#include "if-main.h"
+#include "terminal.h"
+
+/* how many times tab was hit */
+static int tab_hit_count;
+
+typedef struct split_arg {
+       struct split_arg *next; /* next argument in buffer */
+       const char *origin; /* pointer to original argument */
+       char ntcopy[1]; /* null terminated copy of argument */
+} split_arg_t;
+
+/* function returns method of given name or NULL if not found */
+const struct method *get_interface_method(const char *iname,
+                                                       const char *mname)
+{
+       const struct interface *iface = get_interface(iname);
+
+       if (iface == NULL)
+               return NULL;
+
+       return get_method(iface->methods, mname);
+}
+
+/* prints matching elements */
+static void print_matches(enum_func f, void *user, const char *prefix, int len)
+{
+       int i;
+       const char *enum_name;
+
+       putchar('\n');
+       for (i = 0; NULL != (enum_name = f(user, i)); ++i) {
+               if (strncmp(enum_name, prefix, len) == 0)
+                       printf("%s\t", enum_name);
+       }
+       putchar('\n');
+       terminal_draw_command_line();
+}
+
+/*
+ * This function splits command line into linked list of arguments.
+ * line_buffer - pointer to input command line
+ * size - size of command line to parse
+ * buf - output buffer to keep split arguments list
+ * buf_size_in_bytes - size of buf
+ */
+static int split_command(const char *line_buffer, int size, split_arg_t *buf,
+                                                       int buf_size_in_bytes)
+{
+       split_arg_t *prev = NULL;
+       split_arg_t *arg = buf;
+       int argc = 0;
+       const char *p = line_buffer;
+       const char *e = p + (size > 0 ? size : (int) strlen(p));
+       int len;
+
+       do {
+               while (p < e && isspace(*p))
+                       p++;
+               arg->origin = p;
+               arg->next = NULL;
+               while (p < e && !isspace(*p))
+                       p++;
+               len = p - arg->origin;
+               if (&arg->ntcopy[0] + len + 1 >
+                       (const char *) buf + buf_size_in_bytes)
+                       break;
+               strncpy(arg->ntcopy, arg->origin, len);
+               arg->ntcopy[len] = 0;
+               if (prev != NULL)
+                       prev->next = arg;
+               prev = arg;
+               arg += (2 * sizeof(*arg) + len) / sizeof(*arg);
+               argc++;
+       } while (p < e);
+
+       return argc;
+}
+
+/* Function to enumerate method names */
+static const char *methods_name(void *v, int i)
+{
+       const struct interface *iface = v;
+
+       return iface->methods[i].name[0] ? iface->methods[i].name : NULL;
+}
+
+struct command_completion_args;
+typedef void (*short_help)(struct command_completion_args *args);
+
+struct command_completion_args {
+       const split_arg_t *arg; /* list of arguments */
+       const char *typed; /* last typed element */
+       enum_func func; /* enumerating function */
+       void *user; /* argument to enumerating function */
+       short_help help; /* help function */
+       void *user_help; /* additional data (used by short_help) */
+};
+
+/*
+ * complete command line
+ */
+static void tab_completion(struct command_completion_args *args)
+{
+       const char *name = args->typed;
+       const int len = strlen(name);
+       int i;
+       int j;
+       char prefix[128] = {0};
+       int prefix_len = 0;
+       int count = 0;
+       const char *enum_name;
+
+       for (i = 0; NULL != (enum_name = args->func(args->user, i)); ++i) {
+               /* prefix does not match */
+               if (strncmp(enum_name, name, len) != 0)
+                       continue;
+
+               /* prefix matches first time */
+               if (count++ == 0) {
+                       strcpy(prefix, enum_name);
+                       prefix_len = strlen(prefix);
+                       continue;
+               }
+
+               /*
+                * Prefix matches next time
+                * reduce prefix to common part
+                */
+               for (j = 0; prefix[j] != 0
+                       && prefix[j] == enum_name[j];)
+                       ++j;
+               prefix_len = j;
+               prefix[j] = 0;
+       }
+
+       if (count == 0) {
+               /* no matches */
+               if (args->help != NULL)
+                       args->help(args);
+               tab_hit_count = 0;
+               return;
+       }
+
+       /* len == prefix_len => nothing new was added */
+       if (len == prefix_len) {
+               if (count != 1) {
+                       if (tab_hit_count == 1) {
+                               putchar('\a');
+                       } else if (tab_hit_count == 2 ||
+                                       args->help == NULL) {
+                               print_matches(args->func,
+                                               args->user, name, len);
+                       } else {
+                               args->help(args);
+                               tab_hit_count = 1;
+                       }
+               } else if (count == 1) {
+                       /* nothing to add, exact match add space */
+                       terminal_insert_into_command_line(" ");
+               }
+       } else {
+               /* new chars can be added from some interface name(s) */
+               if (count == 1) {
+                       /* exact match, add space */
+                       prefix[prefix_len++] = ' ';
+                       prefix[prefix_len] = '\0';
+               }
+
+               terminal_insert_into_command_line(prefix + len);
+               tab_hit_count = 0;
+       }
+}
+
+/* interface completion */
+static void command_completion(split_arg_t *arg)
+{
+       struct command_completion_args args = {
+               .arg = arg,
+               .typed = arg->ntcopy,
+               .func = command_name
+       };
+
+       tab_completion(&args);
+}
+
+/* method completion */
+static void method_completion(const struct interface *iface, split_arg_t *arg)
+{
+       struct command_completion_args args = {
+               .arg = arg,
+               .typed = arg->next->ntcopy,
+               .func = methods_name,
+               .user = (void *) iface
+       };
+
+       if (iface == NULL)
+               return;
+
+       tab_completion(&args);
+}
+
+static const char *bold = "\x1b[1m";
+static const char *normal = "\x1b[0m";
+
+static bool find_nth_argument(const char *str, int n, const char **s,
+                                                               const char **e)
+{
+       const char *p = str;
+       int argc = 0;
+       *e = NULL;
+
+       while (p != NULL && *p != 0) {
+
+               while (isspace(*p))
+                       ++p;
+
+               if (n == argc)
+                       *s = p;
+
+               if (*p == '[') {
+                       p = strchr(p, ']');
+                       if (p != NULL)
+                               *e = ++p;
+               } else if (*p == '<') {
+                       p = strchr(p, '>');
+                       if (p != NULL)
+                               *e = ++p;
+               } else {
+                       *e = strchr(p, ' ');
+                       if (*e == NULL)
+                               *e = p + strlen(p);
+                       p = *e;
+               }
+
+               if (n == argc)
+                       break;
+
+               argc++;
+               *e = NULL;
+       }
+       return *e != NULL;
+}
+
+/* prints short help on method for interface */
+static void method_help(struct command_completion_args *args)
+{
+       int argc;
+       const split_arg_t *arg = args->arg;
+       const char *sb = NULL;
+       const char *eb = NULL;
+       const char *arg1 = "";
+       int arg1_size = 0; /* size of method field (for methods > 0) */
+
+       if (args->user_help == NULL)
+               return;
+
+       for (argc = 0; arg != NULL; argc++)
+               arg = arg->next;
+
+       /* Check if this is method from interface */
+       if (get_command(args->arg->ntcopy) == NULL) {
+               /* if so help is missing interface and method name */
+               arg1 = args->arg->next->ntcopy;
+               arg1_size = strlen(arg1) + 1;
+       }
+
+       find_nth_argument(args->user_help, argc - (arg1_size ? 3 : 2),
+                                                               &sb, &eb);
+
+       if (eb != NULL)
+               haltest_info("%s %-*s%.*s%s%.*s%s%s\n", args->arg->ntcopy,
+                               arg1_size, arg1,
+                               sb - (const char *) args->user_help,
+                               args->user_help,
+                               bold, eb - sb, sb, normal, eb);
+       else
+               haltest_info("%s %-*s%s\n", args->arg->ntcopy,
+                       arg1_size, arg1, args->user_help);
+}
+
+/* So we have empty enumeration */
+static const char *return_null(void *user, int i)
+{
+       return NULL;
+}
+
+/*
+ * parameter completion function
+ * argc - number of elements in arg list
+ * arg - list of arguments
+ * method - method to get completion from (can be NULL)
+ */
+static void param_completion(int argc, const split_arg_t *arg,
+                                       const struct method *method, int hlpix)
+{
+       int i;
+       const char *argv[argc];
+       const split_arg_t *tmp = arg;
+       struct command_completion_args args = {
+               .arg = arg,
+               .func = return_null
+       };
+
+       /* prepare standard argv from arg */
+       for (i = 0; i < argc; ++i) {
+               argv[i] = tmp->ntcopy;
+               tmp = tmp->next;
+       }
+
+       if (method != NULL && method->complete != NULL) {
+               /* ask method for completion function */
+               method->complete(argc, argv, &args.func, &args.user);
+       }
+
+       /* If method provided enumeration function call try to complete */
+       if (args.func != NULL) {
+               args.typed = argv[argc - 1];
+               args.help = method_help;
+               args.user_help = method ? (void *) method->help : NULL;
+
+               tab_completion(&args);
+       }
+}
+
+/*
+ * This method gets called when user tapped tab key.
+ * line - points to command line
+ * len - size of line that should be used for completions. This should be
+ *   cursor position during tab hit.
+ */
+void process_tab(const char *line, int len)
+{
+       int argc;
+       static split_arg_t buf[(LINE_BUF_MAX * 2) / sizeof(split_arg_t)];
+       const struct method *method;
+
+       argc = split_command(line, len, buf, sizeof(buf));
+       tab_hit_count++;
+
+       if (argc == 0)
+               return;
+
+       if (argc == 1) {
+               command_completion(buf);
+               return;
+       }
+
+       method = get_command(buf[0].ntcopy);
+       if (method != NULL) {
+               param_completion(argc, buf, method, 1);
+       } else if (argc == 2) {
+               method_completion(get_interface(buf[0].ntcopy), buf);
+       } else {
+               /* Find method for <interface, name> pair */
+               method = get_interface_method(buf[0].ntcopy,
+                                                       buf[0].next->ntcopy);
+               param_completion(argc, buf, method, 2);
+       }
+}
diff --git a/android/client/terminal.c b/android/client/terminal.c
new file mode 100644 (file)
index 0000000..f7b56de
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <termios.h>
+#include <stdlib.h>
+
+#include "terminal.h"
+#include "history.h"
+
+/*
+ * Character sequences recognized by code in this file
+ * Leading ESC 0x1B is not included
+ */
+#define SEQ_INSERT "[2~"
+#define SEQ_DELETE "[3~"
+#define SEQ_HOME   "OH"
+#define SEQ_END    "OF"
+#define SEQ_PGUP   "[5~"
+#define SEQ_PGDOWN "[6~"
+#define SEQ_LEFT   "[D"
+#define SEQ_RIGHT  "[C"
+#define SEQ_UP     "[A"
+#define SEQ_DOWN   "[B"
+#define SEQ_STAB   "[Z"
+#define SEQ_M_n    "n"
+#define SEQ_M_p    "p"
+#define SEQ_CLEFT  "[1;5D"
+#define SEQ_CRIGHT "[1;5C"
+#define SEQ_CUP    "[1;5A"
+#define SEQ_CDOWN  "[1;5B"
+#define SEQ_SLEFT  "[1;2D"
+#define SEQ_SRIGHT "[1;2C"
+#define SEQ_SUP    "[1;2A"
+#define SEQ_SDOWN  "[1;2B"
+#define SEQ_MLEFT  "[1;3D"
+#define SEQ_MRIGHT "[1;3C"
+#define SEQ_MUP    "[1;3A"
+#define SEQ_MDOWN  "[1;3B"
+
+#define KEY_SEQUENCE(k) { KEY_##k, SEQ_##k }
+struct ansii_sequence {
+       int code;
+       const char *sequence;
+};
+
+/* Table connects single int key codes with character sequences */
+static const struct ansii_sequence ansii_sequnces[] = {
+       KEY_SEQUENCE(INSERT),
+       KEY_SEQUENCE(DELETE),
+       KEY_SEQUENCE(HOME),
+       KEY_SEQUENCE(END),
+       KEY_SEQUENCE(PGUP),
+       KEY_SEQUENCE(PGDOWN),
+       KEY_SEQUENCE(LEFT),
+       KEY_SEQUENCE(RIGHT),
+       KEY_SEQUENCE(UP),
+       KEY_SEQUENCE(DOWN),
+       KEY_SEQUENCE(CLEFT),
+       KEY_SEQUENCE(CRIGHT),
+       KEY_SEQUENCE(CUP),
+       KEY_SEQUENCE(CDOWN),
+       KEY_SEQUENCE(SLEFT),
+       KEY_SEQUENCE(SRIGHT),
+       KEY_SEQUENCE(SUP),
+       KEY_SEQUENCE(SDOWN),
+       KEY_SEQUENCE(MLEFT),
+       KEY_SEQUENCE(MRIGHT),
+       KEY_SEQUENCE(MUP),
+       KEY_SEQUENCE(MDOWN),
+       KEY_SEQUENCE(STAB),
+       KEY_SEQUENCE(M_p),
+       KEY_SEQUENCE(M_n),
+       { 0, NULL }
+};
+
+#define KEY_SEQUNCE_NOT_FINISHED -1
+#define KEY_C_C 3
+#define KEY_C_D 4
+#define KEY_C_L 12
+
+#define isseqence(c) ((c) == 0x1B)
+
+/*
+ * Number of characters that consist of ANSI sequence
+ * Should not be less then longest string in ansi_sequences
+ */
+#define MAX_ASCII_SEQUENCE 10
+
+static char current_sequence[MAX_ASCII_SEQUENCE];
+static int current_sequence_len = -1;
+
+/* single line typed by user goes here */
+static char line_buf[LINE_BUF_MAX];
+/* index of cursor in input line */
+static int line_buf_ix = 0;
+/* current length of input line */
+static int line_len = 0;
+
+/* line index used for fetching lines from history */
+static int line_index = 0;
+
+static char prompt_buf[10] = "> ";
+static const char *const noprompt = "";
+static const char *current_prompt = prompt_buf;
+static const char *prompt = prompt_buf;
+/*
+ * Moves cursor to right or left
+ *
+ * n - positive - moves cursor right
+ * n - negative - moves cursor left
+ */
+static void terminal_move_cursor(int n)
+{
+       if (n < 0) {
+               for (; n < 0; n++)
+                       putchar('\b');
+       } else if (n > 0) {
+               printf("%*s", n, line_buf + line_buf_ix);
+       }
+}
+
+/* Draw command line */
+void terminal_draw_command_line(void)
+{
+       /*
+        * this needs to be checked here since line_buf is not cleared
+        * before parsing event though line_len and line_buf_ix are
+        */
+       if (line_len > 0)
+               printf("%s%s", prompt, line_buf);
+       else
+               printf("%s", prompt);
+
+       /* move cursor to it's place */
+       terminal_move_cursor(line_buf_ix - line_len);
+}
+
+/* inserts string into command line at cursor position */
+void terminal_insert_into_command_line(const char *p)
+{
+       int len = strlen(p);
+
+       if (line_len == line_buf_ix) {
+               strcat(line_buf, p);
+               printf("%s", p);
+               line_len = line_len + len;
+               line_buf_ix = line_len;
+       } else {
+               memmove(line_buf + line_buf_ix + len,
+                       line_buf + line_buf_ix, line_len - line_buf_ix + 1);
+               memmove(line_buf + line_buf_ix, p, len);
+               printf("%s", line_buf + line_buf_ix);
+               line_buf_ix += len;
+               line_len += len;
+               terminal_move_cursor(line_buf_ix - line_len);
+       }
+}
+
+/* Prints string and redraws command line */
+int terminal_print(const char *format, ...)
+{
+       va_list args;
+       int ret;
+
+       va_start(args, format);
+
+       ret = terminal_vprint(format, args);
+
+       va_end(args);
+       return ret;
+}
+
+/* Prints string and redraws command line */
+int terminal_vprint(const char *format, va_list args)
+{
+       int ret;
+
+       printf("\r%*s\r", (int) line_len + 1, " ");
+
+       ret = vprintf(format, args);
+
+       terminal_draw_command_line();
+
+       fflush(stdout);
+
+       return ret;
+}
+
+/*
+ * Call this when text in line_buf was changed
+ * and line needs to be redrawn
+ */
+static void terminal_line_replaced(void)
+{
+       int len = strlen(line_buf);
+
+       /* line is shorter that previous */
+       if (len < line_len) {
+               /* if new line is shorter move cursor to end of new end */
+               while (line_buf_ix > len) {
+                       putchar('\b');
+                       line_buf_ix--;
+               }
+
+               /* If cursor was not at the end, move it to the end */
+               if (line_buf_ix < line_len)
+                       printf("%.*s", line_len - line_buf_ix,
+                                       line_buf + line_buf_ix);
+               /* over write end of previous line */
+               while (line_len >= len++)
+                       putchar(' ');
+       }
+
+       /* draw new line */
+       printf("\r%s%s", prompt, line_buf);
+       /* set up indexes to new line */
+       line_len = strlen(line_buf);
+       line_buf_ix = line_len;
+       fflush(stdout);
+}
+
+static void terminal_clear_line(void)
+{
+       line_buf[0] = '\0';
+       terminal_line_replaced();
+}
+
+static void terminal_clear_screen(void)
+{
+       line_buf[0] = '\0';
+       line_buf_ix = 0;
+       line_len = 0;
+
+       printf("\x1b[2J\x1b[1;1H%s", prompt);
+}
+
+static void terminal_delete_char(void)
+{
+       /* delete character under cursor if not at the very end */
+       if (line_buf_ix >= line_len)
+               return;
+       /*
+        * Prepare buffer with one character missing
+        * trailing 0 is moved
+        */
+       line_len--;
+       memmove(line_buf + line_buf_ix, line_buf + line_buf_ix + 1,
+                                               line_len - line_buf_ix + 1);
+       /* print rest of line from current cursor position */
+       printf("%s \b", line_buf + line_buf_ix);
+       /* move back cursor */
+       terminal_move_cursor(line_buf_ix - line_len);
+}
+
+/*
+ * Function tries to replace current line with specified line in history
+ * new_line_index - new line to show, -1 to show oldest
+ */
+static void terminal_get_line_from_history(int new_line_index)
+{
+       new_line_index = history_get_line(new_line_index,
+                                               line_buf, LINE_BUF_MAX);
+
+       if (new_line_index >= 0) {
+               terminal_line_replaced();
+               line_index = new_line_index;
+       }
+}
+
+/*
+ * Function searches history back or forward for command line that starts
+ * with characters up to cursor position
+ *
+ * back - true - searches backward
+ * back - false - searches forward (more recent commands)
+ */
+static void terminal_match_hitory(bool back)
+{
+       char buf[line_buf_ix + 1];
+       int line;
+       int matching_line = -1;
+       int dir = back ? 1 : -1;
+
+       line = line_index + dir;
+       while (matching_line == -1 && line >= 0) {
+               int new_line_index;
+
+               new_line_index = history_get_line(line, buf, line_buf_ix + 1);
+               if (new_line_index < 0)
+                       break;
+
+               if (0 == strncmp(line_buf, buf, line_buf_ix))
+                       matching_line = line;
+               line += dir;
+       }
+
+       if (matching_line >= 0) {
+               int pos = line_buf_ix;
+               terminal_get_line_from_history(matching_line);
+               /* move back to cursor position to original place */
+               line_buf_ix = pos;
+               terminal_move_cursor(pos - line_len);
+       }
+}
+
+/*
+ * Converts terminal character sequences to single value representing
+ * keyboard keys
+ */
+static int terminal_convert_sequence(int c)
+{
+       int i;
+
+       /* Not in sequence yet? */
+       if (current_sequence_len == -1) {
+               /* Is ansi sequence detected by 0x1B ? */
+               if (isseqence(c)) {
+                       current_sequence_len++;
+                       return KEY_SEQUNCE_NOT_FINISHED;
+               }
+
+               return c;
+       }
+
+       /* Inside sequence */
+       current_sequence[current_sequence_len++] = c;
+       current_sequence[current_sequence_len] = '\0';
+       for (i = 0; ansii_sequnces[i].code; ++i) {
+               /* Matches so far? */
+               if (0 != strncmp(current_sequence, ansii_sequnces[i].sequence,
+                                                       current_sequence_len))
+                       continue;
+
+               /* Matches as a whole? */
+               if (ansii_sequnces[i].sequence[current_sequence_len] == 0) {
+                       current_sequence_len = -1;
+                       return ansii_sequnces[i].code;
+               }
+
+               /* partial match (not whole sequence yet) */
+               return KEY_SEQUNCE_NOT_FINISHED;
+       }
+
+       terminal_print("ansi char 0x%X %c\n", c);
+       /*
+        * Sequence does not match
+        * mark that no in sequence any more, return char
+        */
+       current_sequence_len = -1;
+       return c;
+}
+
+typedef void (*terminal_action)(int c, line_callback process_line);
+
+#define TERMINAL_ACTION(n) \
+       static void n(int c, void (*process_line)(char *line))
+
+TERMINAL_ACTION(terminal_action_null)
+{
+}
+
+/* Mapping between keys and function */
+typedef struct {
+       int key;
+       terminal_action func;
+} KeyAction;
+
+int action_keys[] = {
+       KEY_SEQUNCE_NOT_FINISHED,
+       KEY_LEFT,
+       KEY_RIGHT,
+       KEY_HOME,
+       KEY_END,
+       KEY_DELETE,
+       KEY_CLEFT,
+       KEY_CRIGHT,
+       KEY_SUP,
+       KEY_SDOWN,
+       KEY_UP,
+       KEY_DOWN,
+       KEY_BACKSPACE,
+       KEY_INSERT,
+       KEY_PGUP,
+       KEY_PGDOWN,
+       KEY_CUP,
+       KEY_CDOWN,
+       KEY_SLEFT,
+       KEY_SRIGHT,
+       KEY_MLEFT,
+       KEY_MRIGHT,
+       KEY_MUP,
+       KEY_MDOWN,
+       KEY_STAB,
+       KEY_M_n,
+       KEY_M_p,
+       KEY_C_C,
+       KEY_C_D,
+       KEY_C_L,
+       '\t',
+       '\r',
+       '\n',
+};
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+/*
+ * current_actions holds all recognizable kes and actions for them
+ * additional element (index 0) is used for default action
+ */
+static KeyAction current_actions[NELEM(action_keys) + 1];
+
+/* KeyAction comparator by key, for qsort and bsearch */
+static int KeyActionKeyCompare(const void *a, const void *b)
+{
+       return ((const KeyAction *) a)->key - ((const KeyAction *) b)->key;
+}
+
+/* Find action by key, NULL if no action for this key */
+static KeyAction *terminal_get_action(int key)
+{
+       KeyAction a = { .key = key };
+
+       return bsearch(&a, current_actions + 1, NELEM(action_keys), sizeof(a),
+                                                       KeyActionKeyCompare);
+}
+
+/* Sets new set of actions to use */
+static void terminal_set_actions(const KeyAction *actions)
+{
+       int i;
+
+       /* Make map with empty function for every key */
+       for (i = 0; i < NELEM(action_keys); ++i) {
+               /*
+                * + 1 due to 0 index reserved for default action that is
+                * called for non mapped key
+                */
+               current_actions[i + 1].key = action_keys[i];
+               current_actions[i + 1].func = terminal_action_null;
+       }
+
+       /* Sort action from 1 (index 0 - default action) */
+       qsort(current_actions + 1, NELEM(action_keys), sizeof(KeyAction),
+                                                       KeyActionKeyCompare);
+       /* Set default action (first in array) */
+       current_actions[0] = *actions++;
+
+       /* Copy rest of actions into their places */
+       for (; actions->key; ++actions) {
+               KeyAction *place = terminal_get_action(actions->key);
+
+               if (place)
+                       place->func = actions->func;
+       }
+}
+
+TERMINAL_ACTION(terminal_action_left)
+{
+       /* if not at the beginning move to previous character */
+       if (line_buf_ix <= 0)
+               return;
+       line_buf_ix--;
+       terminal_move_cursor(-1);
+}
+
+TERMINAL_ACTION(terminal_action_right)
+{
+       /*
+        * If not at the end, just print current character
+        * and modify position
+        */
+       if (line_buf_ix < line_len)
+               putchar(line_buf[line_buf_ix++]);
+}
+
+TERMINAL_ACTION(terminal_action_home)
+{
+       /* move to beginning of line and update position */
+       printf("\r%s", prompt);
+       line_buf_ix = 0;
+}
+
+TERMINAL_ACTION(terminal_action_end)
+{
+       /* if not at the end of line */
+       if (line_buf_ix < line_len) {
+               /* print everything from cursor */
+               printf("%s", line_buf + line_buf_ix);
+               /* just modify current position */
+               line_buf_ix = line_len;
+       }
+}
+
+TERMINAL_ACTION(terminal_action_del)
+{
+       terminal_delete_char();
+}
+
+TERMINAL_ACTION(terminal_action_word_left)
+{
+       int old_pos;
+       /*
+        * Move by word left
+        *
+        * Are we at the beginning of line?
+        */
+       if (line_buf_ix <= 0)
+               return;
+
+       old_pos = line_buf_ix;
+       line_buf_ix--;
+       /* skip spaces left */
+       while (line_buf_ix && isspace(line_buf[line_buf_ix]))
+               line_buf_ix--;
+
+       /* skip all non spaces to the left */
+       while (line_buf_ix > 0 &&
+                       !isspace(line_buf[line_buf_ix - 1]))
+               line_buf_ix--;
+
+       /* move cursor to new position */
+       terminal_move_cursor(line_buf_ix - old_pos);
+}
+
+TERMINAL_ACTION(terminal_action_word_right)
+{
+       int old_pos;
+       /*
+        * Move by word right
+        *
+        * are we at the end of line?
+        */
+       if (line_buf_ix >= line_len)
+               return;
+
+       old_pos = line_buf_ix;
+       /* skip all spaces */
+       while (line_buf_ix < line_len && isspace(line_buf[line_buf_ix]))
+               line_buf_ix++;
+
+       /* skip all non spaces */
+       while (line_buf_ix < line_len && !isspace(line_buf[line_buf_ix]))
+               line_buf_ix++;
+       /*
+        * Move cursor to right by printing text
+        * between old cursor and new
+        */
+       if (line_buf_ix > old_pos)
+               printf("%.*s", (int) (line_buf_ix - old_pos),
+                                                       line_buf + old_pos);
+}
+
+TERMINAL_ACTION(terminal_action_history_begin)
+{
+       terminal_get_line_from_history(-1);
+}
+
+TERMINAL_ACTION(terminal_action_history_end)
+{
+       if (line_index > 0)
+               terminal_get_line_from_history(0);
+}
+
+TERMINAL_ACTION(terminal_action_history_up)
+{
+       terminal_get_line_from_history(line_index + 1);
+}
+
+TERMINAL_ACTION(terminal_action_history_down)
+{
+       if (line_index > 0)
+               terminal_get_line_from_history(line_index - 1);
+}
+
+TERMINAL_ACTION(terminal_action_tab)
+{
+       /* tab processing */
+       process_tab(line_buf, line_buf_ix);
+}
+
+
+TERMINAL_ACTION(terminal_action_backspace)
+{
+       if (line_buf_ix <= 0)
+               return;
+
+       if (line_buf_ix == line_len) {
+               printf("\b \b");
+               line_len = --line_buf_ix;
+               line_buf[line_len] = 0;
+       } else {
+               putchar('\b');
+               line_buf_ix--;
+               line_len--;
+               memmove(line_buf + line_buf_ix,
+                               line_buf + line_buf_ix + 1,
+                               line_len - line_buf_ix + 1);
+               printf("%s \b", line_buf + line_buf_ix);
+               terminal_move_cursor(line_buf_ix - line_len);
+       }
+}
+
+TERMINAL_ACTION(terminal_action_find_history_forward)
+{
+       /* Search history forward */
+       terminal_match_hitory(false);
+}
+
+TERMINAL_ACTION(terminal_action_find_history_backward)
+{
+       /* Search history forward */
+       terminal_match_hitory(true);
+}
+
+TERMINAL_ACTION(terminal_action_ctrl_c)
+{
+       terminal_clear_line();
+}
+
+TERMINAL_ACTION(terminal_action_ctrl_d)
+{
+       if (line_len > 0) {
+               terminal_delete_char();
+       } else  {
+               puts("");
+               exit(0);
+       }
+}
+
+TERMINAL_ACTION(terminal_action_clear_screen)
+{
+       terminal_clear_screen();
+}
+
+TERMINAL_ACTION(terminal_action_enter)
+{
+       /*
+        * On new line add line to history
+        * forget history position
+        */
+       history_add_line(line_buf);
+       line_len = 0;
+       line_buf_ix = 0;
+       line_index = -1;
+       /* print new line */
+       putchar(c);
+       prompt = noprompt;
+       process_line(line_buf);
+       /* clear current line */
+       line_buf[0] = '\0';
+       prompt = current_prompt;
+       printf("%s", prompt);
+}
+
+TERMINAL_ACTION(terminal_action_default)
+{
+       char str[2] = { c, 0 };
+
+       if (!isprint(c))
+               /*
+                * TODO: remove this print once all meaningful sequences
+                * are identified
+                */
+               printf("char-0x%02x\n", c);
+       else if (line_buf_ix < LINE_BUF_MAX - 1)
+               terminal_insert_into_command_line(str);
+}
+
+/* Callback to call when user hit enter during prompt for */
+static line_callback prompt_callback;
+
+static KeyAction normal_actions[] = {
+       { 0, terminal_action_default },
+       { KEY_LEFT, terminal_action_left },
+       { KEY_RIGHT, terminal_action_right },
+       { KEY_HOME, terminal_action_home },
+       { KEY_END, terminal_action_end },
+       { KEY_DELETE, terminal_action_del },
+       { KEY_CLEFT, terminal_action_word_left },
+       { KEY_CRIGHT, terminal_action_word_right },
+       { KEY_SUP, terminal_action_history_begin },
+       { KEY_SDOWN, terminal_action_history_end },
+       { KEY_UP, terminal_action_history_up },
+       { KEY_DOWN, terminal_action_history_down },
+       { '\t', terminal_action_tab },
+       { KEY_BACKSPACE, terminal_action_backspace },
+       { KEY_M_n, terminal_action_find_history_forward },
+       { KEY_M_p, terminal_action_find_history_backward },
+       { KEY_C_C, terminal_action_ctrl_c },
+       { KEY_C_D, terminal_action_ctrl_d },
+       { KEY_C_L, terminal_action_clear_screen },
+       { '\r', terminal_action_enter },
+       { '\n', terminal_action_enter },
+       { 0, NULL },
+};
+
+TERMINAL_ACTION(terminal_action_answer)
+{
+       putchar(c);
+
+       terminal_set_actions(normal_actions);
+       /* Restore default prompt */
+       current_prompt = prompt_buf;
+
+       /* No prompt for prints */
+       prompt = noprompt;
+       line_buf_ix = 0;
+       line_len = 0;
+       /* Call user function with what was typed */
+       prompt_callback(line_buf);
+
+       line_buf[0] = 0;
+       /* promot_callback could change current_prompt */
+       prompt = current_prompt;
+
+       printf("%s", prompt);
+}
+
+TERMINAL_ACTION(terminal_action_prompt_ctrl_c)
+{
+       printf("^C\n");
+       line_buf_ix = 0;
+       line_len = 0;
+       line_buf[0] = 0;
+
+       current_prompt = prompt_buf;
+       prompt = current_prompt;
+       terminal_set_actions(normal_actions);
+
+       printf("%s", prompt);
+}
+
+static KeyAction prompt_actions[] = {
+       { 0, terminal_action_default },
+       { KEY_LEFT, terminal_action_left },
+       { KEY_RIGHT, terminal_action_right },
+       { KEY_HOME, terminal_action_home },
+       { KEY_END, terminal_action_end },
+       { KEY_DELETE, terminal_action_del },
+       { KEY_CLEFT, terminal_action_word_left },
+       { KEY_CRIGHT, terminal_action_word_right },
+       { KEY_BACKSPACE, terminal_action_backspace },
+       { KEY_C_C, terminal_action_prompt_ctrl_c },
+       { KEY_C_D, terminal_action_ctrl_d },
+       { '\r', terminal_action_answer },
+       { '\n', terminal_action_answer },
+       { 0, NULL },
+};
+
+void terminal_process_char(int c, line_callback process_line)
+{
+       KeyAction *a;
+
+       c = terminal_convert_sequence(c);
+
+       /* Get action for this key */
+       a = terminal_get_action(c);
+
+       /* No action found, get default one */
+       if (a == NULL)
+               a = &current_actions[0];
+
+       a->func(c, process_line);
+       fflush(stdout);
+}
+
+void terminal_prompt_for(const char *s, line_callback process_line)
+{
+       current_prompt = s;
+       if (prompt != noprompt) {
+               prompt = s;
+               terminal_clear_line();
+       }
+       prompt_callback = process_line;
+       terminal_set_actions(prompt_actions);
+}
+
+static struct termios origianl_tios;
+
+static void terminal_cleanup(void)
+{
+       tcsetattr(0, TCSANOW, &origianl_tios);
+}
+
+void terminal_setup(void)
+{
+       struct termios tios;
+
+       terminal_set_actions(normal_actions);
+
+       tcgetattr(0, &origianl_tios);
+       tios = origianl_tios;
+
+       /*
+        * Turn off echo since all editing is done by hand,
+        * Ctrl-c handled internally
+        */
+       tios.c_lflag &= ~(ICANON | ECHO | BRKINT | IGNBRK);
+       tcsetattr(0, TCSANOW, &tios);
+
+       /* Restore terminal at exit */
+       atexit(terminal_cleanup);
+
+       printf("%s", prompt);
+       fflush(stdout);
+}
diff --git a/android/client/terminal.h b/android/client/terminal.h
new file mode 100644 (file)
index 0000000..0e63936
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 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 <stdarg.h>
+
+/* size of supported line */
+#define LINE_BUF_MAX 1024
+
+enum key_codes {
+       KEY_BACKSPACE = 0x7F,
+       KEY_INSERT = 1000, /* arbitrary value */
+       KEY_DELETE,
+       KEY_HOME,
+       KEY_END,
+       KEY_PGUP,
+       KEY_PGDOWN,
+       KEY_LEFT,
+       KEY_RIGHT,
+       KEY_UP,
+       KEY_DOWN,
+       KEY_CLEFT,
+       KEY_CRIGHT,
+       KEY_CUP,
+       KEY_CDOWN,
+       KEY_SLEFT,
+       KEY_SRIGHT,
+       KEY_SUP,
+       KEY_SDOWN,
+       KEY_MLEFT,
+       KEY_MRIGHT,
+       KEY_MUP,
+       KEY_MDOWN,
+       KEY_STAB,
+       KEY_M_p,
+       KEY_M_n
+};
+
+typedef void (*line_callback)(char *);
+
+void terminal_setup(void);
+int terminal_print(const char *format, ...);
+int terminal_vprint(const char *format, va_list args);
+void terminal_process_char(int c, line_callback process_line);
+void terminal_insert_into_command_line(const char *p);
+void terminal_draw_command_line(void);
+void terminal_prompt_for(const char *s, line_callback process_line);
+
+void process_tab(const char *line, int len);
diff --git a/android/cutils/properties.h b/android/cutils/properties.h
new file mode 100644 (file)
index 0000000..7951585
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/* property_set: returns 0 on success, < 0 on failure
+*/
+static inline int property_set(const char *key, const char *value)
+{
+       static const char SYSTEM_SOCKET_PATH[] = "\0android_system";
+
+       struct sockaddr_un addr;
+       char msg[256];
+       int fd, len;
+
+       fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       memcpy(addr.sun_path, SYSTEM_SOCKET_PATH, sizeof(SYSTEM_SOCKET_PATH));
+
+       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(fd);
+               return 0;
+       }
+
+       len = snprintf(msg, sizeof(msg), "%s=%s", key, value);
+
+       if (send(fd, msg, len + 1, 0) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
diff --git a/android/hal-a2dp.c b/android/hal-a2dp.c
new file mode 100644 (file)
index 0000000..e9fadb7
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013 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 <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const btav_callbacks_t *cbs = NULL;
+
+static bool interface_ready(void)
+{
+       return cbs != NULL;
+}
+
+static void handle_conn_state(void *buf)
+{
+       struct hal_ev_a2dp_conn_state *ev = buf;
+
+       if (cbs->connection_state_cb)
+               cbs->connection_state_cb(ev->state,
+                                               (bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_audio_state(void *buf)
+{
+       struct hal_ev_a2dp_audio_state *ev = buf;
+
+       if (cbs->audio_state_cb)
+               cbs->audio_state_cb(ev->state, (bt_bdaddr_t *)(ev->bdaddr));
+}
+
+/* will be called from notification thread context */
+void bt_notify_a2dp(uint8_t opcode, void *buf, uint16_t len)
+{
+       if (!interface_ready())
+               return;
+
+       switch (opcode) {
+       case HAL_EV_A2DP_CONN_STATE:
+               handle_conn_state(buf);
+               break;
+       case HAL_EV_A2DP_AUDIO_STATE:
+               handle_audio_state(buf);
+               break;
+       default:
+               DBG("Unhandled callback opcode=0x%x", opcode);
+               break;
+       }
+}
+
+static bt_status_t a2dp_connect(bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_a2dp_connect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_CONNECT,
+                                       sizeof(cmd), &cmd, NULL, NULL, NULL);
+}
+
+static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_a2dp_disconnect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_DISCONNECT,
+                                       sizeof(cmd), &cmd, NULL, NULL, NULL);
+}
+
+static bt_status_t init(btav_callbacks_t *callbacks)
+{
+       struct hal_cmd_register_module cmd;
+
+       DBG("");
+
+       cbs = callbacks;
+
+       cmd.service_id = HAL_SERVICE_ID_A2DP;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static void cleanup()
+{
+       struct hal_cmd_unregister_module cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return;
+
+       cbs = NULL;
+
+       cmd.service_id = HAL_SERVICE_ID_A2DP;
+
+       hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static btav_interface_t iface = {
+       .size = sizeof(iface),
+       .init = init,
+       .connect = a2dp_connect,
+       .disconnect = disconnect,
+       .cleanup = cleanup
+};
+
+btav_interface_t *bt_get_a2dp_interface()
+{
+       return &iface;
+}
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
new file mode 100644 (file)
index 0000000..078d537
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+#include "hal-utils.h"
+
+static const bt_callbacks_t *bt_hal_cbacks = NULL;
+
+#define create_enum_prop(prop, hal_prop, type) do { \
+       type *pe = malloc(sizeof(type)); \
+       prop.val = pe; \
+       prop.len = sizeof(*pe); \
+       *pe = *((uint8_t *) (hal_prop->val)); \
+} while (0)
+
+static void handle_adapter_state_changed(void *buf)
+{
+       struct hal_ev_adapter_state_changed *ev = buf;
+
+       DBG("state: %s", bt_state_t2str(ev->state));
+
+       if (bt_hal_cbacks->adapter_state_changed_cb)
+               bt_hal_cbacks->adapter_state_changed_cb(ev->state);
+}
+
+static void adapter_props_to_hal(bt_property_t *send_props,
+                                       struct hal_property *hal_prop,
+                                       uint8_t num_props, void *buff_end)
+{
+       void *p = hal_prop;
+       uint8_t i;
+
+       for (i = 0; i < num_props; i++) {
+               if (p + sizeof(*hal_prop) + hal_prop->len > buff_end) {
+                       error("invalid adapter properties event, aborting");
+                       exit(EXIT_FAILURE);
+               }
+
+               send_props[i].type = hal_prop->type;
+
+               switch (hal_prop->type) {
+               case HAL_PROP_ADAPTER_TYPE:
+                       create_enum_prop(send_props[i], hal_prop,
+                                                       bt_device_type_t);
+                       break;
+               case HAL_PROP_ADAPTER_SCAN_MODE:
+                       create_enum_prop(send_props[i], hal_prop,
+                                                       bt_scan_mode_t);
+                       break;
+               case HAL_PROP_ADAPTER_SERVICE_REC:
+               default:
+                       send_props[i].len = hal_prop->len;
+                       send_props[i].val = hal_prop->val;
+                       break;
+               }
+
+               DBG("prop[%d]: %s", i, btproperty2str(&send_props[i]));
+       }
+}
+
+static void adapter_hal_props_cleanup(bt_property_t *props, uint8_t num)
+{
+       uint8_t i;
+
+       for (i = 0; i < num; i++) {
+               switch (props[i].type) {
+               case HAL_PROP_ADAPTER_TYPE:
+               case HAL_PROP_ADAPTER_SCAN_MODE:
+                       free(props[i].val);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void device_props_to_hal(bt_property_t *send_props,
+                                       struct hal_property *hal_prop,
+                                       uint8_t num_props, void *buff_end)
+{
+       void *p = hal_prop;
+       uint8_t i;
+
+       for (i = 0; i < num_props; i++) {
+               if (p + sizeof(*hal_prop) + hal_prop->len > buff_end) {
+                       error("invalid adapter properties event, aborting");
+                       exit(EXIT_FAILURE);
+               }
+
+               send_props[i].type = hal_prop->type;
+
+               switch (hal_prop->type) {
+               case HAL_PROP_DEVICE_TYPE:
+                       create_enum_prop(send_props[i], hal_prop,
+                                                       bt_device_type_t);
+                       break;
+               case HAL_PROP_DEVICE_SERVICE_REC:
+               case HAL_PROP_DEVICE_VERSION_INFO:
+               default:
+                       send_props[i].len = hal_prop->len;
+                       send_props[i].val = hal_prop->val;
+                       break;
+               }
+
+               p += sizeof(*hal_prop) + hal_prop->len;
+               hal_prop = p;
+
+               DBG("prop[%d]: %s", i, btproperty2str(&send_props[i]));
+       }
+}
+
+
+static void device_hal_props_cleanup(bt_property_t *props, uint8_t num)
+{
+       uint8_t i;
+
+       for (i = 0; i < num; i++) {
+               switch (props[i].type) {
+               case HAL_PROP_DEVICE_TYPE:
+                       free(props[i].val);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void handle_adapter_props_changed(void *buf, uint16_t len)
+{
+       struct hal_ev_adapter_props_changed *ev = buf;
+       bt_property_t props[ev->num_props];
+
+       DBG("");
+
+       if (!bt_hal_cbacks->adapter_properties_cb)
+               return;
+
+       adapter_props_to_hal(props, ev->props, ev->num_props, buf + len);
+
+       bt_hal_cbacks->adapter_properties_cb(ev->status, ev->num_props, props);
+
+       adapter_hal_props_cleanup(props, ev->num_props);
+}
+
+static void handle_bond_state_change(void *buf)
+{
+       struct hal_ev_bond_state_changed *ev = buf;
+       bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr;
+
+       DBG("state %u", ev->state);
+
+       if (bt_hal_cbacks->bond_state_changed_cb)
+               bt_hal_cbacks->bond_state_changed_cb(ev->status, addr,
+                                                               ev->state);
+}
+
+static void handle_pin_request(void *buf)
+{
+       struct hal_ev_pin_request *ev = buf;
+       /* Those are declared as packed, so it's safe to assign pointers */
+       bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr;
+       bt_bdname_t *name = (bt_bdname_t *) ev->name;
+
+       DBG("");
+
+       if (bt_hal_cbacks->pin_request_cb)
+               bt_hal_cbacks->pin_request_cb(addr, name, ev->class_of_dev);
+}
+
+static void handle_ssp_request(void *buf)
+{
+       struct hal_ev_ssp_request *ev = buf;
+       /* Those are declared as packed, so it's safe to assign pointers */
+       bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr;
+       bt_bdname_t *name = (bt_bdname_t *) ev->name;
+
+       DBG("");
+
+       if (bt_hal_cbacks->ssp_request_cb)
+               bt_hal_cbacks->ssp_request_cb(addr, name, ev->class_of_dev,
+                                                       ev->pairing_variant,
+                                                       ev->passkey);
+}
+
+void bt_thread_associate(void)
+{
+       if (bt_hal_cbacks->thread_evt_cb)
+               bt_hal_cbacks->thread_evt_cb(ASSOCIATE_JVM);
+}
+
+void bt_thread_disassociate(void)
+{
+       if (bt_hal_cbacks->thread_evt_cb)
+               bt_hal_cbacks->thread_evt_cb(DISASSOCIATE_JVM);
+}
+
+static bool interface_ready(void)
+{
+       return bt_hal_cbacks != NULL;
+}
+
+static void handle_discovery_state_changed(void *buf)
+{
+       struct hal_ev_discovery_state_changed *ev = buf;
+
+       DBG("");
+
+       if (bt_hal_cbacks->discovery_state_changed_cb)
+               bt_hal_cbacks->discovery_state_changed_cb(ev->state);
+}
+
+static void handle_device_found(void *buf, uint16_t len)
+{
+       struct hal_ev_device_found *ev = buf;
+       bt_property_t props[ev->num_props];
+
+       DBG("");
+
+       if (!bt_hal_cbacks->device_found_cb)
+               return;
+
+       device_props_to_hal(props, ev->props, ev->num_props, buf + len);
+
+       bt_hal_cbacks->device_found_cb(ev->num_props, props);
+
+       device_hal_props_cleanup(props, ev->num_props);
+}
+
+static void handle_device_state_changed(void *buf, uint16_t len)
+{
+       struct hal_ev_remote_device_props *ev = buf;
+       bt_property_t props[ev->num_props];
+
+       DBG("");
+
+       if (!bt_hal_cbacks->remote_device_properties_cb)
+               return;
+
+       device_props_to_hal(props, ev->props, ev->num_props, buf + len);
+
+       bt_hal_cbacks->remote_device_properties_cb(ev->status,
+                                               (bt_bdaddr_t *)ev->bdaddr,
+                                               ev->num_props, props);
+
+       device_hal_props_cleanup(props, ev->num_props);
+}
+
+static void handle_acl_state_changed(void *buf)
+{
+       struct hal_ev_acl_state_changed *ev = buf;
+       bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr;
+
+       DBG("state %u", ev->state);
+
+       if (bt_hal_cbacks->acl_state_changed_cb)
+               bt_hal_cbacks->acl_state_changed_cb(ev->status, addr,
+                                                               ev->state);
+}
+
+/* will be called from notification thread context */
+void bt_notify_adapter(uint8_t opcode, void *buf, uint16_t len)
+{
+       if (!interface_ready())
+               return;
+
+       DBG("opcode 0x%x", opcode);
+
+       switch (opcode) {
+       case HAL_EV_ADAPTER_STATE_CHANGED:
+               handle_adapter_state_changed(buf);
+               break;
+       case HAL_EV_ADAPTER_PROPS_CHANGED:
+               handle_adapter_props_changed(buf, len);
+               break;
+       case HAL_EV_DISCOVERY_STATE_CHANGED:
+               handle_discovery_state_changed(buf);
+               break;
+       case HAL_EV_DEVICE_FOUND:
+               handle_device_found(buf, len);
+               break;
+       case HAL_EV_REMOTE_DEVICE_PROPS:
+               handle_device_state_changed(buf, len);
+               break;
+       case HAL_EV_BOND_STATE_CHANGED:
+               handle_bond_state_change(buf);
+               break;
+       case HAL_EV_PIN_REQUEST:
+               handle_pin_request(buf);
+               break;
+       case HAL_EV_SSP_REQUEST:
+               handle_ssp_request(buf);
+               break;
+       case HAL_EV_ACL_STATE_CHANGED:
+               handle_acl_state_changed(buf);
+               break;
+       default:
+               DBG("Unhandled callback opcode=0x%x", opcode);
+               break;
+       }
+}
+
+static int init(bt_callbacks_t *callbacks)
+{
+       struct hal_cmd_register_module cmd;
+       int status;
+
+       DBG("");
+
+       if (interface_ready())
+               return BT_STATUS_SUCCESS;
+
+       bt_hal_cbacks = callbacks;
+
+       if (!hal_ipc_init()) {
+               bt_hal_cbacks = NULL;
+               return BT_STATUS_FAIL;
+       }
+
+       cmd.service_id = HAL_SERVICE_ID_BLUETOOTH;
+
+       status = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+                                       sizeof(cmd), &cmd, NULL, NULL, NULL);
+       if (status != BT_STATUS_SUCCESS) {
+               error("Failed to register 'bluetooth' service");
+               goto fail;
+       }
+
+       cmd.service_id = HAL_SERVICE_ID_SOCK;
+
+       status = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+                                       sizeof(cmd), &cmd, NULL, NULL, NULL);
+       if (status != BT_STATUS_SUCCESS) {
+               error("Failed to register 'socket' service");
+               goto fail;
+       }
+
+       return status;
+
+fail:
+       hal_ipc_cleanup();
+       bt_hal_cbacks = NULL;
+       return status;
+}
+
+static int enable(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_ENABLE, 0, NULL, 0,
+                                                               NULL, NULL);
+}
+
+static int disable(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DISABLE, 0, NULL, 0,
+                                                               NULL, NULL);
+}
+
+static void cleanup(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return;
+
+       hal_ipc_cleanup();
+
+       bt_hal_cbacks = NULL;
+}
+
+static int get_adapter_properties(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROPS,
+                                               0, NULL, 0, NULL, NULL);
+}
+
+static int get_adapter_property(bt_property_type_t type)
+{
+       struct hal_cmd_get_adapter_prop cmd;
+
+       DBG("prop: %s (%d)", bt_property_type_t2str(type), type);
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       switch (type) {
+       case BT_PROPERTY_BDNAME:
+       case BT_PROPERTY_BDADDR:
+       case BT_PROPERTY_UUIDS:
+       case BT_PROPERTY_CLASS_OF_DEVICE:
+       case BT_PROPERTY_TYPE_OF_DEVICE:
+       case BT_PROPERTY_SERVICE_RECORD:
+       case BT_PROPERTY_ADAPTER_SCAN_MODE:
+       case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+       case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       /* type match IPC type */
+       cmd.type = type;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROP,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int set_adapter_property(const bt_property_t *property)
+{
+       char buf[sizeof(struct hal_cmd_set_adapter_prop) + property->len];
+       struct hal_cmd_set_adapter_prop *cmd = (void *) buf;
+
+       DBG("prop: %s", btproperty2str(property));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       switch (property->type) {
+       case BT_PROPERTY_BDNAME:
+       case BT_PROPERTY_ADAPTER_SCAN_MODE:
+       case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       /* type match IPC type */
+       cmd->type = property->type;
+       cmd->len = property->len;
+       memcpy(cmd->val, property->val, property->len);
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SET_ADAPTER_PROP,
+                                       sizeof(buf), cmd, 0, NULL, NULL);
+}
+
+static int get_remote_device_properties(bt_bdaddr_t *remote_addr)
+{
+       DBG("bdaddr: %s", bdaddr2str(remote_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static int get_remote_device_property(bt_bdaddr_t *remote_addr,
+                                               bt_property_type_t type)
+{
+       DBG("bdaddr: %s prop: %s", bdaddr2str(remote_addr),
+                                               bt_property_type_t2str(type));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static int set_remote_device_property(bt_bdaddr_t *remote_addr,
+                                               const bt_property_t *property)
+{
+       DBG("bdaddr: %s prop: %s", bdaddr2str(remote_addr),
+                                               btproperty2str(property));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static int get_remote_service_record(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid)
+{
+       DBG("bdaddr: %s", bdaddr2str(remote_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static int get_remote_services(bt_bdaddr_t *remote_addr)
+{
+       struct hal_cmd_get_remote_services cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(remote_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, remote_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH,
+                       HAL_OP_GET_REMOTE_SERVICES, sizeof(cmd), &cmd, 0,
+                       NULL, NULL);
+}
+
+static int start_discovery(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH,
+                               HAL_OP_START_DISCOVERY, 0, NULL, 0,
+                               NULL, NULL);
+}
+
+static int cancel_discovery(void)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH,
+                               HAL_OP_CANCEL_DISCOVERY, 0, NULL, 0,
+                               NULL, NULL);
+}
+
+static int create_bond(const bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_create_bond cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(bd_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CREATE_BOND,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int cancel_bond(const bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_cancel_bond cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(bd_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CANCEL_BOND,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int remove_bond(const bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_remove_bond cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(bd_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_REMOVE_BOND,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int pin_reply(const bt_bdaddr_t *bd_addr, uint8_t accept,
+                               uint8_t pin_len, bt_pin_code_t *pin_code)
+{
+       struct hal_cmd_pin_reply cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(bd_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+       cmd.accept = accept;
+       cmd.pin_len = pin_len;
+       memcpy(cmd.pin_code, pin_code, sizeof(cmd.pin_code));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_PIN_REPLY,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int ssp_reply(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
+                                       uint8_t accept, uint32_t passkey)
+{
+       struct hal_cmd_ssp_reply cmd;
+
+       DBG("bdaddr: %s", bdaddr2str(bd_addr));
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+       /* type match IPC type */
+       cmd.ssp_variant = variant;
+       cmd.accept = accept;
+       cmd.passkey = passkey;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SSP_REPLY,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static const void *get_profile_interface(const char *profile_id)
+{
+       DBG("%s: %s", __func__, profile_id);
+
+       if (!interface_ready())
+               return NULL;
+
+       if (!strcmp(profile_id, BT_PROFILE_SOCKETS_ID))
+               return bt_get_sock_interface();
+
+       if (!strcmp(profile_id, BT_PROFILE_HIDHOST_ID))
+               return bt_get_hidhost_interface();
+
+       if (!strcmp(profile_id, BT_PROFILE_PAN_ID))
+               return bt_get_pan_interface();
+
+       if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+               return bt_get_a2dp_interface();
+
+       return NULL;
+}
+
+static int dut_mode_configure(uint8_t enable)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static int dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static const bt_interface_t bluetooth_if = {
+       .size = sizeof(bt_interface_t),
+       .init = init,
+       .enable = enable,
+       .disable = disable,
+       .cleanup = cleanup,
+       .get_adapter_properties = get_adapter_properties,
+       .get_adapter_property = get_adapter_property,
+       .set_adapter_property = set_adapter_property,
+       .get_remote_device_properties = get_remote_device_properties,
+       .get_remote_device_property = get_remote_device_property,
+       .set_remote_device_property = set_remote_device_property,
+       .get_remote_service_record = get_remote_service_record,
+       .get_remote_services = get_remote_services,
+       .start_discovery = start_discovery,
+       .cancel_discovery = cancel_discovery,
+       .create_bond = create_bond,
+       .remove_bond = remove_bond,
+       .cancel_bond = cancel_bond,
+       .pin_reply = pin_reply,
+       .ssp_reply = ssp_reply,
+       .get_profile_interface = get_profile_interface,
+       .dut_mode_configure = dut_mode_configure,
+       .dut_mode_send = dut_mode_send
+};
+
+static const bt_interface_t *get_bluetooth_interface(void)
+{
+       DBG("");
+
+       return &bluetooth_if;
+}
+
+static int close_bluetooth(struct hw_device_t *device)
+{
+       DBG("");
+
+       cleanup();
+
+       return 0;
+}
+
+static int open_bluetooth(const struct hw_module_t *module, char const *name,
+                                       struct hw_device_t **device)
+{
+       bluetooth_device_t *dev = malloc(sizeof(bluetooth_device_t));
+
+       DBG("");
+
+       memset(dev, 0, sizeof(bluetooth_device_t));
+       dev->common.tag = HARDWARE_DEVICE_TAG;
+       dev->common.version = 0;
+       dev->common.module = (struct hw_module_t *) module;
+       dev->common.close = close_bluetooth;
+       dev->get_bluetooth_interface = get_bluetooth_interface;
+
+       *device = (struct hw_device_t *) dev;
+
+       return 0;
+}
+
+static struct hw_module_methods_t bluetooth_module_methods = {
+       .open = open_bluetooth,
+};
+
+struct hw_module_t HAL_MODULE_INFO_SYM = {
+       .tag = HARDWARE_MODULE_TAG,
+       .version_major = 1,
+       .version_minor = 0,
+       .id = BT_HARDWARE_MODULE_ID,
+       .name = "BlueZ Bluetooth stack",
+       .author = "Intel Corporation",
+       .methods = &bluetooth_module_methods
+};
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
new file mode 100644 (file)
index 0000000..2ce17a3
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2013 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 <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const bthh_callbacks_t *cbacks;
+
+static bool interface_ready(void)
+{
+       return cbacks != NULL;
+}
+
+static void handle_conn_state(void *buf)
+{
+       struct hal_ev_hidhost_conn_state *ev = buf;
+
+       if (cbacks->connection_state_cb)
+               cbacks->connection_state_cb((bt_bdaddr_t *) ev->bdaddr,
+                                                               ev->state);
+}
+
+static void handle_info(void *buf)
+{
+       struct hal_ev_hidhost_info *ev = buf;
+       bthh_hid_info_t info;
+
+       info.attr_mask = ev->attr;
+       info.sub_class = ev->subclass;
+       info.app_id = ev->app_id;
+       info.vendor_id = ev->vendor;
+       info.product_id = ev->product;
+       info.version = ev->version;
+       info.ctry_code = ev->country;
+       info.dl_len = ev->descr_len;
+       memcpy(info.dsc_list, ev->descr, info.dl_len);
+
+       if (cbacks->hid_info_cb)
+               cbacks->hid_info_cb((bt_bdaddr_t *) ev->bdaddr, info);
+}
+
+static void handle_proto_mode(void *buf)
+{
+       struct hal_ev_hidhost_proto_mode *ev = buf;
+
+       if (cbacks->protocol_mode_cb)
+               cbacks->protocol_mode_cb((bt_bdaddr_t *) ev->bdaddr,
+                                                       ev->status, ev->mode);
+}
+
+static void handle_get_report(void *buf)
+{
+       struct hal_ev_hidhost_get_report *ev = buf;
+
+       if (cbacks->get_report_cb)
+               cbacks->get_report_cb((bt_bdaddr_t *) ev->bdaddr, ev->status,
+                                                       ev->data, ev->len);
+}
+
+static void handle_virtual_unplug(void *buf)
+{
+       struct hal_ev_hidhost_virtual_unplug *ev = buf;
+
+       if (cbacks->virtual_unplug_cb)
+               cbacks->virtual_unplug_cb((bt_bdaddr_t *) ev->bdaddr,
+                                                               ev->status);
+}
+
+/* will be called from notification thread context */
+void bt_notify_hidhost(uint8_t opcode, void *buf, uint16_t len)
+{
+       if (!interface_ready())
+               return;
+
+       switch (opcode) {
+       case HAL_EV_HIDHOST_CONN_STATE:
+               handle_conn_state(buf);
+               break;
+       case HAL_EV_HIDHOST_INFO:
+               handle_info(buf);
+               break;
+       case HAL_EV_HIDHOST_PROTO_MODE:
+               handle_proto_mode(buf);
+               break;
+       case HAL_EV_HIDHOST_GET_REPORT:
+               handle_get_report(buf);
+               break;
+       case HAL_EV_HIDHOST_VIRTUAL_UNPLUG:
+               handle_virtual_unplug(buf);
+               break;
+       default:
+               DBG("Unhandled callback opcode=0x%x", opcode);
+               break;
+       }
+}
+
+static bt_status_t hidhost_connect(bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_hidhost_connect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_CONNECT,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_hidhost_disconnect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_DISCONNECT,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t virtual_unplug(bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_hidhost_virtual_unplug cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
+                                       HAL_OP_HIDHOST_VIRTUAL_UNPLUG,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
+{
+       struct hal_cmd_hidhost_set_info cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+       cmd.attr = hid_info.attr_mask;
+       cmd.subclass = hid_info.sub_class;
+       cmd.app_id = hid_info.app_id;
+       cmd.vendor = hid_info.vendor_id;
+       cmd.product = hid_info.product_id;
+       cmd.country = hid_info.ctry_code;
+       cmd.descr_len = hid_info.dl_len;
+       memcpy(cmd.descr, hid_info.dsc_list, cmd.descr_len);
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SET_INFO,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t get_protocol(bt_bdaddr_t *bd_addr,
+                                       bthh_protocol_mode_t protocol_mode)
+{
+       struct hal_cmd_hidhost_get_protocol cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       switch (protocol_mode) {
+       case BTHH_REPORT_MODE:
+               cmd.mode = HAL_HIDHOST_REPORT_PROTOCOL;
+               break;
+       case BTHH_BOOT_MODE:
+               cmd.mode = HAL_HIDHOST_BOOT_PROTOCOL;
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
+                               HAL_OP_HIDHOST_GET_PROTOCOL,
+                               sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t set_protocol(bt_bdaddr_t *bd_addr,
+                                       bthh_protocol_mode_t protocol_mode)
+{
+       struct hal_cmd_hidhost_set_protocol cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       switch (protocol_mode) {
+       case BTHH_REPORT_MODE:
+               cmd.mode = HAL_HIDHOST_REPORT_PROTOCOL;
+               break;
+       case BTHH_BOOT_MODE:
+               cmd.mode = HAL_HIDHOST_BOOT_PROTOCOL;
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
+                               HAL_OP_HIDHOST_SET_PROTOCOL,
+                               sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t get_report(bt_bdaddr_t *bd_addr,
+                                               bthh_report_type_t report_type,
+                                               uint8_t report_id,
+                                               int buffer_size)
+{
+       struct hal_cmd_hidhost_get_report cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+       cmd.id = report_id;
+       cmd.buf_size = buffer_size;
+
+       switch (report_type) {
+       case BTHH_INPUT_REPORT:
+               cmd.type = HAL_HIDHOST_INPUT_REPORT;
+               break;
+       case BTHH_OUTPUT_REPORT:
+               cmd.type = HAL_HIDHOST_OUTPUT_REPORT;
+               break;
+       case BTHH_FEATURE_REPORT:
+               cmd.type = HAL_HIDHOST_FEATURE_REPORT;
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_GET_REPORT,
+                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t set_report(bt_bdaddr_t *bd_addr,
+                                               bthh_report_type_t report_type,
+                                               char *report)
+{
+       uint8_t buf[BLUEZ_HAL_MTU];
+       struct hal_cmd_hidhost_set_report *cmd = (void *) buf;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr || !report)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd->bdaddr, bd_addr, sizeof(cmd->bdaddr));
+       cmd->len = strlen(report);
+       memcpy(cmd->data, report, cmd->len);
+
+       switch (report_type) {
+       case BTHH_INPUT_REPORT:
+               cmd->type = HAL_HIDHOST_INPUT_REPORT;
+               break;
+       case BTHH_OUTPUT_REPORT:
+               cmd->type = HAL_HIDHOST_OUTPUT_REPORT;
+               break;
+       case BTHH_FEATURE_REPORT:
+               cmd->type = HAL_HIDHOST_FEATURE_REPORT;
+               break;
+       default:
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SET_REPORT,
+                               sizeof(*cmd) + cmd->len, buf, 0, NULL, NULL);
+}
+
+static bt_status_t send_data(bt_bdaddr_t *bd_addr, char *data)
+{
+       uint8_t buf[BLUEZ_HAL_MTU];
+       struct hal_cmd_hidhost_send_data *cmd = (void *) buf;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       if (!bd_addr || !data)
+               return BT_STATUS_PARM_INVALID;
+
+       memcpy(cmd->bdaddr, bd_addr, sizeof(cmd->bdaddr));
+       cmd->len = strlen(data);
+       memcpy(cmd->data, data, cmd->len);
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SEND_DATA,
+                               sizeof(*cmd) + cmd->len, buf, 0, NULL, NULL);
+}
+
+static bt_status_t init(bthh_callbacks_t *callbacks)
+{
+       struct hal_cmd_register_module cmd;
+
+       DBG("");
+
+       /* store reference to user callbacks */
+       cbacks = callbacks;
+
+       cmd.service_id = HAL_SERVICE_ID_HIDHOST;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static void cleanup(void)
+{
+       struct hal_cmd_unregister_module cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return;
+
+       cbacks = NULL;
+
+       cmd.service_id = HAL_SERVICE_ID_HIDHOST;
+
+       hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bthh_interface_t hidhost_if = {
+       .size = sizeof(hidhost_if),
+       .init = init,
+       .connect = hidhost_connect,
+       .disconnect = disconnect,
+       .virtual_unplug = virtual_unplug,
+       .set_info = set_info,
+       .get_protocol = get_protocol,
+       .set_protocol = set_protocol,
+       .get_report = get_report,
+       .set_report = set_report,
+       .send_data = send_data,
+       .cleanup = cleanup
+};
+
+bthh_interface_t *bt_get_hidhost_interface(void)
+{
+       return &hidhost_if;
+}
index 9a8b770..57f4c13 100644 (file)
@@ -117,7 +117,9 @@ Core Service (ID 0)
 
        Opcode 0x00 - Error response
 
-               Response parameters: Error (1 octet)
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01       Failed
 
        Opcode 0x01 - Register module command/response
 
@@ -279,6 +281,11 @@ Commands and responses:
                                    Passkey (4 octets)
                Response parameters: <none>
 
+               Valid SSP variant values: 0x00 = Passkey Confirmation
+                                         0x01 = Passkey Entry
+                                         0x02 = Consent (for Just Works)
+                                         0x03 = Passkey Notification
+
                In case of an error, the error response will be returned.
 
        Opcode 0x12 - DUT Mode Configure command/response
@@ -312,6 +319,9 @@ Notifications:
 
                Notifications parameters: State (1 octect)
 
+               Valid state values: 0x00 = Off
+                                   0x01 = On
+
        Opcode 0x82 - Adapter Properties Changed notification
 
                Notification parameters: Status (1 octect)
@@ -344,13 +354,13 @@ Notifications:
 
                Notification parameters: Remote address (6 octets)
                                         Remote name (249 octets)
-                                        Class of device (3 octets)
+                                        Class of device (4 octets)
 
        Opcode 0x87 - SSP Request notification
 
                Notification parameters: Remote address (6 octets)
                                         Remote name (249 octets)
-                                        Class of device (3 octets)
+                                        Class of device (4 octets)
                                         Pairing variant (1 octet)
                                         Passkey (4 octets)
 
@@ -360,6 +370,10 @@ Notifications:
                                         Remote address (6 octets)
                                         Bond state (1 octet)
 
+               Valid bond state values: 0x00 = None
+                                        0x01 = Bonding
+                                        0x02 = Bonded
+
        Opcode 0x89 - ACL State Changed notification
 
                Notification parameters: Status (1 octect)
@@ -538,7 +552,9 @@ Commands and responses:
 
                Command parameters: Remote address (6 octets)
                                    Report type (1 octet)
-                                   ...
+                                   Report length (2 octets)
+                                   Report data (Report length)
+
                Response parameters: <none>
 
                Valid report types: 0x01 = Input
@@ -550,7 +566,9 @@ Commands and responses:
        Opcode 0x09 - Send Data command/response
 
                Command parameters: Remote address (6 octets)
-                                   ...
+                                   Data length (2 octets)
+                                   Data (Data length)
+
                Response parameters: <none>
 
                In case of an error, the error response will be returned.
@@ -560,6 +578,7 @@ Notifications:
        Opcode 0x81 - Connection State notification
 
                Notification parameters: Remote address (6 octets)
+                                        Connection State (1 octets)
 
                Valid connection states: 0x00 = Connected
                                         0x01 = Connecting
@@ -595,20 +614,14 @@ Notifications:
                                      0x01 = Boot
                                      0xff = Unsupported
 
-       Opcode 0x84 - Idle Time notification
-
-               Notification parameters: Remote address (6 octets)
-                                        Status (1 octet)
-                                        Idle time (2 octets)
-
-       Opcode 0x85 - Get Report notification
+       Opcode 0x84 - Get Report notification
 
                Notification parameters: Remote address (6 octets)
                                         Status (1 octet)
                                         Report length (2 octets)
                                         Report data (variable)
 
-       Opcode 0x86 - Virtual Unplug notification
+       Opcode 0x85 - Virtual Unplug notification
 
                Notification parameters: Remote address (6 octets)
                                         Status (1 octet)
@@ -1013,7 +1026,7 @@ Notifications:
 Bluetooth Advanced Audio HAL (ID 6)
 ===================================
 
-Android HAL name: "ad2p" (BT_PROFILE_ADVANCED_AUDIO_ID)
+Android HAL name: "a2dp" (BT_PROFILE_ADVANCED_AUDIO_ID)
 
 Commands and responses:
 
diff --git a/android/hal-ipc.c b/android/hal-ipc.c
new file mode 100644 (file)
index 0000000..026e245
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2013 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 <pthread.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <cutils/properties.h>
+
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-log.h"
+#include "hal-ipc.h"
+
+#define CONNECT_TIMEOUT (5 * 1000)
+#define SERVICE_NAME "bluetoothd"
+
+static int cmd_sk = -1;
+static int notif_sk = -1;
+
+static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_t notif_th = 0;
+
+static void notification_dispatch(struct hal_hdr *msg, int fd)
+{
+       switch (msg->service_id) {
+       case HAL_SERVICE_ID_BLUETOOTH:
+               bt_notify_adapter(msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_HIDHOST:
+               bt_notify_hidhost(msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_A2DP:
+               bt_notify_a2dp(msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_PAN:
+               bt_notify_pan(msg->opcode, msg->payload, msg->len);
+               break;
+       default:
+               DBG("Unhandled notification service=%d opcode=0x%x",
+                                               msg->service_id, msg->opcode);
+               break;
+       }
+}
+
+static void *notification_handler(void *data)
+{
+       struct msghdr msg;
+       struct iovec iv;
+       struct cmsghdr *cmsg;
+       char cmsgbuf[CMSG_SPACE(sizeof(int))];
+       char buf[BLUEZ_HAL_MTU];
+       struct hal_hdr *ev = (void *) buf;
+       ssize_t ret;
+       int fd;
+
+       bt_thread_associate();
+
+       while (true) {
+               memset(&msg, 0, sizeof(msg));
+               memset(buf, 0, sizeof(buf));
+               memset(cmsgbuf, 0, sizeof(cmsgbuf));
+
+               iv.iov_base = ev;
+               iv.iov_len = sizeof(buf);
+
+               msg.msg_iov = &iv;
+               msg.msg_iovlen = 1;
+
+               msg.msg_control = cmsgbuf;
+               msg.msg_controllen = sizeof(cmsgbuf);
+
+               ret = recvmsg(notif_sk, &msg, 0);
+               if (ret < 0) {
+                       error("Receiving notifications failed, aborting :%s",
+                                                       strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+
+               /* socket was shutdown */
+               if (ret == 0) {
+                       if (cmd_sk == -1)
+                               break;
+
+                       error("Notification socket closed, aborting");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (ret < (ssize_t) sizeof(*ev)) {
+                       error("Too small notification (%zd bytes), aborting",
+                                                                       ret);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (ev->opcode < HAL_MINIMUM_EVENT) {
+                       error("Invalid notification (0x%x), aborting",
+                                                       ev->opcode);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (ret != (ssize_t) (sizeof(*ev) + ev->len)) {
+                       error("Malformed notification(%zd bytes), aborting",
+                                                                       ret);
+                       exit(EXIT_FAILURE);
+               }
+
+               fd = -1;
+
+               /* Receive auxiliary data in msg */
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+                                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level == SOL_SOCKET
+                                       && cmsg->cmsg_type == SCM_RIGHTS) {
+                               memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+                               break;
+                       }
+               }
+
+               notification_dispatch(ev, fd);
+       }
+
+       close(notif_sk);
+       notif_sk = -1;
+
+       bt_thread_disassociate();
+
+       DBG("exit");
+
+       return NULL;
+}
+
+static int accept_connection(int sk)
+{
+       int err;
+       struct pollfd pfd;
+       int new_sk;
+
+       memset(&pfd, 0 , sizeof(pfd));
+       pfd.fd = sk;
+       pfd.events = POLLIN;
+
+       err = poll(&pfd, 1, CONNECT_TIMEOUT);
+       if (err < 0) {
+               err = errno;
+               error("Failed to poll: %d (%s)", err, strerror(err));
+               return -1;
+       }
+
+       if (err == 0) {
+               error("bluetoothd connect timeout");
+               return -1;
+       }
+
+       new_sk = accept(sk, NULL, NULL);
+       if (new_sk < 0) {
+               err = errno;
+               error("Failed to accept socket: %d (%s)", err, strerror(err));
+               return -1;
+       }
+
+       return new_sk;
+}
+
+bool hal_ipc_init(void)
+{
+       struct sockaddr_un addr;
+       int sk;
+       int err;
+
+       sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+       if (sk < 0) {
+               err = errno;
+               error("Failed to create socket: %d (%s)", err,
+                                                       strerror(err));
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+
+       memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               err = errno;
+               error("Failed to bind socket: %d (%s)", err, strerror(err));
+               close(sk);
+               return false;
+       }
+
+       if (listen(sk, 2) < 0) {
+               err = errno;
+               error("Failed to listen on socket: %d (%s)", err,
+                                                               strerror(err));
+               close(sk);
+               return false;
+       }
+
+       /* Start Android Bluetooth daemon service */
+       if (property_set("ctl.start", SERVICE_NAME) < 0) {
+               error("Failed to start service %s", SERVICE_NAME);
+               close(sk);
+               return false;
+       }
+
+       cmd_sk = accept_connection(sk);
+       if (cmd_sk < 0) {
+               close(sk);
+               return false;
+       }
+
+       notif_sk = accept_connection(sk);
+       if (notif_sk < 0) {
+               close(sk);
+               close(cmd_sk);
+               cmd_sk = -1;
+               return false;
+       }
+
+       info("bluetoothd connected");
+
+       close(sk);
+
+       err = pthread_create(&notif_th, NULL, notification_handler, NULL);
+       if (err < 0) {
+               notif_th = 0;
+               error("Failed to start notification thread: %d (%s)", -err,
+                                                       strerror(-err));
+               close(cmd_sk);
+               cmd_sk = -1;
+               close(notif_sk);
+               notif_sk = -1;
+               return false;
+       }
+
+       return true;
+}
+
+void hal_ipc_cleanup(void)
+{
+       close(cmd_sk);
+       cmd_sk = -1;
+
+       shutdown(notif_sk, SHUT_RD);
+
+       pthread_join(notif_th, NULL);
+       notif_th = 0;
+}
+
+int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
+                                       size_t *rsp_len, void *rsp, int *fd)
+{
+       ssize_t ret;
+       struct msghdr msg;
+       struct iovec iv[2];
+       struct hal_hdr cmd;
+       char cmsgbuf[CMSG_SPACE(sizeof(int))];
+       struct hal_status s;
+       size_t s_len = sizeof(s);
+
+       if (cmd_sk < 0) {
+               error("Invalid cmd socket passed to hal_ipc_cmd, aborting");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!rsp || !rsp_len) {
+               memset(&s, 0, s_len);
+               rsp_len = &s_len;
+               rsp = &s;
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.service_id = service_id;
+       cmd.opcode = opcode;
+       cmd.len = len;
+
+       iv[0].iov_base = &cmd;
+       iv[0].iov_len = sizeof(cmd);
+
+       iv[1].iov_base = param;
+       iv[1].iov_len = len;
+
+       msg.msg_iov = iv;
+       msg.msg_iovlen = 2;
+
+       pthread_mutex_lock(&cmd_sk_mutex);
+
+       ret = sendmsg(cmd_sk, &msg, 0);
+       if (ret < 0) {
+               error("Sending command failed, aborting :%s", strerror(errno));
+               pthread_mutex_unlock(&cmd_sk_mutex);
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&cmd, 0, sizeof(cmd));
+
+       iv[0].iov_base = &cmd;
+       iv[0].iov_len = sizeof(cmd);
+
+       iv[1].iov_base = rsp;
+       iv[1].iov_len = *rsp_len;
+
+       msg.msg_iov = iv;
+       msg.msg_iovlen = 2;
+
+       if (fd) {
+               memset(cmsgbuf, 0, sizeof(cmsgbuf));
+               msg.msg_control = cmsgbuf;
+               msg.msg_controllen = sizeof(cmsgbuf);
+       }
+
+       ret = recvmsg(cmd_sk, &msg, 0);
+       if (ret < 0) {
+               error("Receiving command response failed, aborting :%s",
+                                                       strerror(errno));
+               pthread_mutex_unlock(&cmd_sk_mutex);
+               exit(EXIT_FAILURE);
+       }
+
+       pthread_mutex_unlock(&cmd_sk_mutex);
+
+       if (ret < (ssize_t) sizeof(cmd)) {
+               error("Too small response received(%zd bytes), aborting", ret);
+               exit(EXIT_FAILURE);
+       }
+
+       if (cmd.service_id != service_id) {
+               error("Invalid service id (%u vs %u), aborting",
+                                               cmd.service_id, service_id);
+               exit(EXIT_FAILURE);
+       }
+
+       if (ret != (ssize_t) (sizeof(cmd) + cmd.len)) {
+               error("Malformed response received(%zd bytes), aborting", ret);
+               exit(EXIT_FAILURE);
+       }
+
+       if (cmd.opcode != opcode && cmd.opcode != HAL_OP_STATUS) {
+               error("Invalid opcode received (%u vs %u), aborting",
+                                               cmd.opcode, opcode);
+               exit(EXIT_FAILURE);
+       }
+
+       if (cmd.opcode == HAL_OP_STATUS) {
+               struct hal_status *s = rsp;
+               return s->code;
+       }
+
+       /* Receive auxiliary data in msg */
+       if (fd) {
+               struct cmsghdr *cmsg;
+
+               *fd = -1;
+
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+                                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level == SOL_SOCKET
+                                       && cmsg->cmsg_type == SCM_RIGHTS) {
+                               memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
+                               break;
+                       }
+               }
+       }
+
+       if (rsp_len)
+               *rsp_len = cmd.len;
+
+       return BT_STATUS_SUCCESS;
+}
diff --git a/android/hal-ipc.h b/android/hal-ipc.h
new file mode 100644 (file)
index 0000000..ea53e1c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 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.
+ *
+ */
+
+bool hal_ipc_init(void);
+void hal_ipc_cleanup(void);
+
+int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
+                                       size_t *rsp_len, void *rsp, int *fd);
diff --git a/android/hal-log.h b/android/hal-log.h
new file mode 100644 (file)
index 0000000..9bd024d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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 "BlueZ"
+
+#ifdef __BIONIC__
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#define LOG_INFO " I"
+#define LOG_WARN " W"
+#define LOG_ERROR " E"
+#define LOG_DEBUG " D"
+#define ALOG(pri, tag, fmt, arg...) printf(tag pri": " fmt"\n", ##arg)
+#endif
+
+#define info(fmt, arg...) ALOG(LOG_INFO, LOG_TAG, fmt, ##arg)
+#define warn(fmt, arg...) ALOG(LOG_WARN, LOG_TAG, fmt, ##arg)
+#define error(fmt, arg...) ALOG(LOG_ERROR, LOG_TAG, fmt, ##arg)
+#define DBG(fmt, arg...) ALOG(LOG_DEBUG, LOG_TAG, "%s:%s() "fmt, __FILE__, \
+                                                       __func__, ##arg)
diff --git a/android/hal-msg.h b/android/hal-msg.h
new file mode 100644 (file)
index 0000000..44fd5c8
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define BLUEZ_HAL_MTU 1024
+
+static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
+
+struct hal_hdr {
+       uint8_t  service_id;
+       uint8_t  opcode;
+       uint16_t len;
+       uint8_t  payload[0];
+} __attribute__((packed));
+
+#define HAL_MINIMUM_EVENT              0x81
+
+#define HAL_SERVICE_ID_CORE            0
+#define HAL_SERVICE_ID_BLUETOOTH       1
+#define HAL_SERVICE_ID_SOCK            2
+#define HAL_SERVICE_ID_HIDHOST         3
+#define HAL_SERVICE_ID_PAN             4
+#define HAL_SERVICE_ID_HANDSFREE       5
+#define HAL_SERVICE_ID_A2DP            6
+#define HAL_SERVICE_ID_HEALTH          7
+#define HAL_SERVICE_ID_AVRCP           8
+#define HAL_SERVICE_ID_GATT            9
+
+#define HAL_SERVICE_ID_MAX HAL_SERVICE_ID_GATT
+
+/* Core Service */
+
+#define HAL_STATUS_SUCCESS             0x00
+#define HAL_STATUS_FAILED              0x01
+#define HAL_STATUS_NOT_READY           0x02
+#define HAL_STATUS_NOMEM               0x03
+#define HAL_STATUS_BUSY                        0x04
+#define HAL_STATUS_DONE                        0x05
+#define HAL_STATUS_UNSUPPORTED         0x06
+#define HAL_STATUS_INVALID             0x07
+#define HAL_STATUS_UNHANDLED           0x08
+#define HAL_STATUS_AUTH_FAILURE                0x09
+#define HAL_STATUS_REMOTE_DEVICE_DOWN  0x0a
+
+#define HAL_OP_STATUS                  0x00
+struct hal_status {
+       uint8_t code;
+} __attribute__((packed));
+
+#define HAL_OP_REGISTER_MODULE         0x01
+struct hal_cmd_register_module {
+       uint8_t service_id;
+} __attribute__((packed));
+
+#define HAL_OP_UNREGISTER_MODULE       0x02
+struct hal_cmd_unregister_module {
+       uint8_t service_id;
+} __attribute__((packed));
+
+/* Bluetooth Core HAL API */
+
+#define HAL_OP_ENABLE                  0x01
+
+#define HAL_OP_DISABLE                 0x02
+
+#define HAL_OP_GET_ADAPTER_PROPS       0x03
+
+#define HAL_OP_GET_ADAPTER_PROP                0x04
+struct hal_cmd_get_adapter_prop {
+       uint8_t type;
+} __attribute__((packed));
+
+#define HAL_MAX_NAME_LENGTH            249
+
+#define HAL_PROP_ADAPTER_NAME                  0x01
+#define HAL_PROP_ADAPTER_ADDR                  0x02
+#define HAL_PROP_ADAPTER_UUIDS                 0x03
+#define HAL_PROP_ADAPTER_CLASS                 0x04
+#define HAL_PROP_ADAPTER_TYPE                  0x05
+#define HAL_PROP_ADAPTER_SERVICE_REC           0x06
+#define HAL_PROP_ADAPTER_SCAN_MODE             0x07
+#define HAL_PROP_ADAPTER_BONDED_DEVICES                0x08
+#define HAL_PROP_ADAPTER_DISC_TIMEOUT          0x09
+
+#define HAL_PROP_DEVICE_NAME                   0x01
+#define HAL_PROP_DEVICE_ADDR                   0x02
+#define HAL_PROP_DEVICE_UUIDS                  0x03
+#define HAL_PROP_DEVICE_CLASS                  0x04
+#define HAL_PROP_DEVICE_TYPE                   0x05
+#define HAL_PROP_DEVICE_SERVICE_REC            0x06
+#define HAL_PROP_DEVICE_FRIENDLY_NAME          0x0a
+#define HAL_PROP_DEVICE_RSSI                   0x0b
+#define HAL_PROP_DEVICE_VERSION_INFO           0x0c
+#define HAL_PROP_DEVICE_TIMESTAMP              0xFF
+
+#define HAL_ADAPTER_SCAN_MODE_NONE             0x00
+#define HAL_ADAPTER_SCAN_MODE_CONN             0x01
+#define HAL_ADAPTER_SCAN_MODE_CONN_DISC        0x02
+
+#define HAL_OP_SET_ADAPTER_PROP                0x05
+struct hal_cmd_set_adapter_prop {
+       uint8_t  type;
+       uint16_t len;
+       uint8_t  val[0];
+} __attribute__((packed));
+
+#define HAL_OP_GET_REMOTE_DEVICE_PROPS 0x06
+struct hal_cmd_get_remote_device_props {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_GET_REMOTE_DEVICE_PROP  0x07
+struct hal_cmd_get_remote_device_prop {
+       uint8_t bdaddr[6];
+       uint8_t type;
+} __attribute__((packed));
+
+#define HAL_OP_SET_REMOTE_DEVICE_PROP  0x08
+struct hal_cmd_set_remote_device_prop {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+       uint16_t len;
+       uint8_t  val[0];
+} __attribute__((packed));
+
+#define HAL_OP_GET_REMOTE_SERVICE_REC  0x09
+struct hal_cmd_get_remote_service_rec {
+       uint8_t bdaddr[6];
+       uint8_t uuid[16];
+} __attribute__((packed));
+
+#define HAL_OP_GET_REMOTE_SERVICES     0x0a
+struct hal_cmd_get_remote_services {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_START_DISCOVERY         0x0b
+
+#define HAL_OP_CANCEL_DISCOVERY                0x0c
+
+#define HAL_OP_CREATE_BOND             0x0d
+struct hal_cmd_create_bond {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_REMOVE_BOND             0x0e
+struct hal_cmd_remove_bond {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_CANCEL_BOND             0x0f
+struct hal_cmd_cancel_bond {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_PIN_REPLY               0x10
+struct hal_cmd_pin_reply {
+       uint8_t bdaddr[6];
+       uint8_t accept;
+       uint8_t pin_len;
+       uint8_t pin_code[16];
+} __attribute__((packed));
+
+#define HAL_SSP_VARIANT_CONFIRM                0x00
+#define HAL_SSP_VARIANT_ENTRY          0x01
+#define HAL_SSP_VARIANT_CONSENT                0x02
+#define HAL_SSP_VARIANT_NOTIF          0x03
+
+#define HAL_OP_SSP_REPLY               0x11
+struct hal_cmd_ssp_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  ssp_variant;
+       uint8_t  accept;
+       uint32_t passkey;
+} __attribute__((packed));
+
+#define HAL_OP_DUT_MODE_CONF           0x12
+struct hal_cmd_dut_mode_conf {
+       uint8_t enable;
+} __attribute__((packed));
+
+#define HAL_OP_DUT_MODE_SEND           0x13
+struct hal_cmd_dut_mode_send {
+       uint16_t opcode;
+       uint8_t  len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_OP_LE_TEST_MODE            0x14
+struct hal_cmd_le_test_mode {
+       uint16_t opcode;
+       uint8_t  len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+/* Bluetooth Socket HAL api */
+
+#define HAL_OP_SOCK_LISTEN             0x01
+struct hal_cmd_sock_listen {
+       uint8_t  type;
+       uint8_t  name[256];
+       uint8_t  uuid[16];
+       uint16_t channel;
+       uint8_t  flags;
+} __attribute__((packed));
+
+#define HAL_OP_SOCK_CONNECT            0x02
+struct hal_cmd_sock_connect {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+       uint8_t  uuid[16];
+       uint16_t channel;
+       uint8_t  flags;
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_CONNECT         0x01
+struct hal_cmd_hidhost_connect {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_DISCONNECT              0x02
+struct hal_cmd_hidhost_disconnect {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_VIRTUAL_UNPLUG          0x03
+struct hal_cmd_hidhost_virtual_unplug {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_SET_INFO                0x04
+struct hal_cmd_hidhost_set_info {
+       uint8_t  bdaddr[6];
+       uint8_t  attr;
+       uint8_t  subclass;
+       uint8_t  app_id;
+       uint16_t vendor;
+       uint16_t product;
+       uint16_t country;
+       uint16_t descr_len;
+       uint8_t  descr[0];
+} __attribute__((packed));
+
+#define HAL_HIDHOST_REPORT_PROTOCOL            0x00
+#define HAL_HIDHOST_BOOT_PROTOCOL              0x01
+#define HAL_HIDHOST_UNSUPPORTED_PROTOCOL       0xff
+
+#define HAL_OP_HIDHOST_GET_PROTOCOL    0x05
+struct hal_cmd_hidhost_get_protocol {
+       uint8_t bdaddr[6];
+       uint8_t mode;
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_SET_PROTOCOL    0x06
+struct hal_cmd_hidhost_set_protocol {
+       uint8_t bdaddr[6];
+       uint8_t mode;
+} __attribute__((packed));
+
+#define HAL_HIDHOST_INPUT_REPORT               0x01
+#define HAL_HIDHOST_OUTPUT_REPORT              0x02
+#define HAL_HIDHOST_FEATURE_REPORT             0x03
+
+#define HAL_OP_HIDHOST_GET_REPORT              0x07
+struct hal_cmd_hidhost_get_report {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+       uint8_t  id;
+       uint16_t buf_size;
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_SET_REPORT              0x08
+struct hal_cmd_hidhost_set_report {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+       uint16_t len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_OP_HIDHOST_SEND_DATA               0x09
+struct hal_cmd_hidhost_send_data {
+       uint8_t  bdaddr[6];
+       uint16_t len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+/* a2dp HAL API */
+
+#define HAL_OP_A2DP_CONNECT    0x01
+struct hal_cmd_a2dp_connect {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_A2DP_DISCONNECT 0x02
+struct hal_cmd_a2dp_disconnect {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+/* PAN HAL API */
+
+/* PAN Roles */
+#define HAL_PAN_ROLE_NONE      0x00
+#define HAL_PAN_ROLE_NAP       0x01
+#define HAL_PAN_ROLE_PANU      0x02
+
+/* PAN Control states */
+#define HAL_PAN_CTRL_ENABLED   0x00
+#define HAL_PAN_CTRL_DISABLED  0x01
+
+/* PAN Connection states */
+#define HAL_PAN_STATE_CONNECTED                0x00
+#define HAL_PAN_STATE_CONNECTING       0x01
+#define HAL_PAN_STATE_DISCONNECTED     0x02
+#define HAL_PAN_STATE_DISCONNECTING    0x03
+
+/* PAN status values */
+#define HAL_PAN_STATUS_FAIL            0x01
+#define HAL_PAN_STATUS_NOT_READY       0x02
+#define HAL_PAN_STATUS_NO_MEMORY       0x03
+#define HAL_PAN_STATUS_BUSY            0x04
+#define HAL_PAN_STATUS_DONE            0x05
+#define HAL_PAN_STATUS_UNSUPORTED      0x06
+#define HAL_PAN_STATUS_INVAL           0x07
+#define HAL_PAN_STATUS_UNHANDLED       0x08
+#define HAL_PAN_STATUS_AUTH_FAILED     0x09
+#define HAL_PAN_STATUS_DEVICE_DOWN     0x0A
+
+#define HAL_OP_PAN_ENABLE      0x01
+struct hal_cmd_pan_enable {
+       uint8_t local_role;
+} __attribute__((packed));
+
+#define HAL_OP_PAN_GET_ROLE    0x02
+struct hal_rsp_pan_get_role {
+       uint8_t local_role;
+} __attribute__((packed));
+
+#define HAL_OP_PAN_CONNECT     0x03
+struct hal_cmd_pan_connect {
+       uint8_t bdaddr[6];
+       uint8_t local_role;
+       uint8_t remote_role;
+} __attribute__((packed));
+
+#define HAL_OP_PAN_DISCONNECT  0x04
+struct hal_cmd_pan_disconnect {
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+/* Notifications and confirmations */
+
+
+#define HAL_POWER_OFF                  0x00
+#define HAL_POWER_ON                   0x01
+
+#define HAL_EV_ADAPTER_STATE_CHANGED   0x81
+struct hal_ev_adapter_state_changed {
+       uint8_t state;
+} __attribute__((packed));
+
+#define HAL_EV_ADAPTER_PROPS_CHANGED   0x82
+struct hal_property {
+       uint8_t  type;
+       uint16_t len;
+       uint8_t  val[0];
+} __attribute__((packed));
+struct hal_ev_adapter_props_changed {
+       uint8_t              status;
+       uint8_t              num_props;
+       struct  hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_EV_REMOTE_DEVICE_PROPS     0x83
+struct hal_ev_remote_device_props {
+       uint8_t             status;
+       uint8_t             bdaddr[6];
+       uint8_t             num_props;
+       struct hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_EV_DEVICE_FOUND            0x84
+struct hal_ev_device_found {
+       uint8_t             num_props;
+       struct hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_DISCOVERY_STATE_STOPPED    0x00
+#define HAL_DISCOVERY_STATE_STARTED    0x01
+
+#define HAL_EV_DISCOVERY_STATE_CHANGED 0x85
+struct hal_ev_discovery_state_changed {
+       uint8_t state;
+} __attribute__((packed));
+
+#define HAL_EV_PIN_REQUEST             0x86
+struct hal_ev_pin_request {
+       uint8_t  bdaddr[6];
+       uint8_t  name[249];
+       uint32_t class_of_dev;
+} __attribute__((packed));
+
+#define HAL_EV_SSP_REQUEST             0x87
+struct hal_ev_ssp_request {
+       uint8_t  bdaddr[6];
+       uint8_t  name[249];
+       uint32_t class_of_dev;
+       uint8_t  pairing_variant;
+       uint32_t passkey;
+} __attribute__((packed));
+
+#define HAL_BOND_STATE_NONE 0
+#define HAL_BOND_STATE_BONDING 1
+#define HAL_BOND_STATE_BONDED 2
+
+#define HAL_EV_BOND_STATE_CHANGED      0x88
+struct hal_ev_bond_state_changed {
+       uint8_t status;
+       uint8_t bdaddr[6];
+       uint8_t state;
+} __attribute__((packed));
+
+#define HAL_ACL_STATE_CONNECTED                0x00
+#define HAL_ACL_STATE_DISCONNECTED     0x01
+
+#define HAL_EV_ACL_STATE_CHANGED       0x89
+struct hal_ev_acl_state_changed {
+       uint8_t status;
+       uint8_t bdaddr[6];
+       uint8_t state;
+} __attribute__((packed));
+
+#define HAL_EV_DUT_MODE_RECEIVE                0x8a
+struct hal_ev_dut_mode_receive {
+       uint16_t opcode;
+       uint8_t  len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_EV_LE_TEST_MODE            0x8b
+struct hal_ev_le_test_mode {
+       uint8_t  status;
+       uint16_t num_packets;
+} __attribute__((packed));
+
+#define HAL_HIDHOST_STATE_CONNECTED            0x00
+#define HAL_HIDHOST_STATE_CONNECTING   0x01
+#define HAL_HIDHOST_STATE_DISCONNECTED 0x02
+#define HAL_HIDHOST_STATE_DISCONNECTING        0x03
+#define HAL_HIDHOST_STATE_NO_HID               0x07
+#define HAL_HIDHOST_STATE_FAILED               0x08
+#define HAL_HIDHOST_STATE_UNKNOWN              0x09
+
+#define HAL_EV_HIDHOST_CONN_STATE              0x81
+struct hal_ev_hidhost_conn_state {
+       uint8_t bdaddr[6];
+       uint8_t state;
+} __attribute__((packed));
+
+#define HAL_HIDHOST_STATUS_OK          0x00
+#define HAL_HIDHOST_GENERAL_ERROR      0x06
+
+#define HAL_EV_HIDHOST_INFO                    0x82
+struct hal_ev_hidhost_info {
+       uint8_t  bdaddr[6];
+       uint8_t  attr;
+       uint8_t  subclass;
+       uint8_t  app_id;
+       uint16_t vendor;
+       uint16_t product;
+       uint16_t version;
+       uint8_t  country;
+       uint16_t descr_len;
+       uint8_t  descr[884];
+} __attribute__((packed));
+
+#define HAL_EV_HIDHOST_PROTO_MODE              0x83
+struct hal_ev_hidhost_proto_mode {
+       uint8_t bdaddr[6];
+       uint8_t status;
+       uint8_t mode;
+} __attribute__((packed));
+
+#define HAL_EV_HIDHOST_GET_REPORT              0x84
+struct hal_ev_hidhost_get_report {
+       uint8_t  bdaddr[6];
+       uint8_t  status;
+       uint16_t len;
+       uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_EV_HIDHOST_VIRTUAL_UNPLUG          0x85
+struct hal_ev_hidhost_virtual_unplug {
+       uint8_t  bdaddr[6];
+       uint8_t  status;
+} __attribute__((packed));
+
+#define HAL_EV_PAN_CTRL_STATE                  0x81
+struct hal_ev_pan_ctrl_state {
+       uint8_t  state;
+       uint8_t  status;
+       uint8_t  local_role;
+       uint8_t  name[17];
+} __attribute__((packed));
+
+#define HAL_EV_PAN_CONN_STATE                  0x82
+struct hal_ev_pan_conn_state {
+       uint8_t  state;
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+       uint8_t  local_role;
+       uint8_t  remote_role;
+} __attribute__((packed));
+
+#define HAL_A2DP_STATE_DISCONNECTED            0x00
+#define HAL_A2DP_STATE_CONNECTING              0x01
+#define HAL_A2DP_STATE_CONNECTED               0x02
+#define HAL_A2DP_STATE_DISCONNECTING           0x03
+
+#define HAL_EV_A2DP_CONN_STATE                 0x81
+struct hal_ev_a2dp_conn_state {
+       uint8_t state;
+       uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_A2DP_AUDIO_STATE                        0x82
+struct hal_ev_a2dp_audio_state {
+       uint8_t state;
+       uint8_t bdaddr[6];
+} __attribute__((packed));
diff --git a/android/hal-pan.c b/android/hal-pan.c
new file mode 100644 (file)
index 0000000..2bc560e
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 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 <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const btpan_callbacks_t *cbs = NULL;
+
+static bool interface_ready(void)
+{
+       return cbs != NULL;
+}
+
+static void handle_conn_state(void *buf)
+{
+       struct hal_ev_pan_conn_state *ev = buf;
+
+       if (cbs->connection_state_cb)
+               cbs->connection_state_cb(ev->state, ev->status,
+                                       (bt_bdaddr_t *) ev->bdaddr,
+                                       ev->local_role, ev->remote_role);
+}
+
+static void handle_ctrl_state(void *buf)
+{
+       struct hal_ev_pan_ctrl_state *ev = buf;
+
+       if (cbs->control_state_cb)
+               cbs->control_state_cb(ev->state, ev->status,
+                                       ev->local_role, (char *)ev->name);
+}
+
+void bt_notify_pan(uint8_t opcode, void *buf, uint16_t len)
+{
+       if (!interface_ready())
+               return;
+
+       switch (opcode) {
+       case HAL_EV_PAN_CONN_STATE:
+               handle_conn_state(buf);
+               break;
+       case HAL_EV_PAN_CTRL_STATE:
+               handle_ctrl_state(buf);
+               break;
+       default:
+               DBG("Unhandled callback opcode=0x%x", opcode);
+               break;
+       }
+}
+
+static bt_status_t pan_enable(int local_role)
+{
+       struct hal_cmd_pan_enable cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       cmd.local_role = local_role;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static int pan_get_local_role(void)
+{
+       struct hal_rsp_pan_get_role rsp;
+       size_t len = sizeof(rsp);
+       bt_status_t status;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BTPAN_ROLE_NONE;
+
+       status = hal_ipc_cmd(HAL_SERVICE_ID_PAN, HAL_OP_PAN_GET_ROLE, 0, NULL,
+                                                       &len, &rsp, NULL);
+       if (status != BT_STATUS_SUCCESS)
+               return BTPAN_ROLE_NONE;
+
+       return rsp.local_role;
+}
+
+static bt_status_t pan_connect(const bt_bdaddr_t *bd_addr, int local_role,
+                                       int remote_role)
+{
+       struct hal_cmd_pan_connect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+       cmd.local_role = local_role;
+       cmd.remote_role = remote_role;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_PAN, HAL_OP_PAN_CONNECT,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t pan_disconnect(const bt_bdaddr_t *bd_addr)
+{
+       struct hal_cmd_pan_disconnect cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return BT_STATUS_NOT_READY;
+
+       memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t pan_init(const btpan_callbacks_t *callbacks)
+{
+       struct hal_cmd_register_module cmd;
+
+       DBG("");
+
+       cbs = callbacks;
+
+       cmd.service_id = HAL_SERVICE_ID_PAN;
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static void pan_cleanup()
+{
+       struct hal_cmd_register_module cmd;
+
+       DBG("");
+
+       if (!interface_ready())
+               return;
+
+       cbs = NULL;
+
+       cmd.service_id = HAL_SERVICE_ID_PAN;
+
+       hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+                                       sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static btpan_interface_t pan_if = {
+       .size = sizeof(pan_if),
+       .init = pan_init,
+       .enable = pan_enable,
+       .get_local_role = pan_get_local_role,
+       .connect = pan_connect,
+       .disconnect = pan_disconnect,
+       .cleanup = pan_cleanup
+};
+
+btpan_interface_t *bt_get_pan_interface()
+{
+       return &pan_if;
+}
diff --git a/android/hal-sock.c b/android/hal-sock.c
new file mode 100644 (file)
index 0000000..b7bc88e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hal-ipc.h"
+#include "hal-log.h"
+#include "hal-msg.h"
+#include "hal-utils.h"
+#include "hal.h"
+
+static bt_status_t sock_listen_rfcomm(const char *service_name,
+                                       const uint8_t *uuid, int chan,
+                                       int *sock, int flags)
+{
+       struct hal_cmd_sock_listen cmd;
+
+       DBG("");
+
+       cmd.flags = flags;
+       cmd.type = BTSOCK_RFCOMM;
+       cmd.channel = chan;
+       memcpy(cmd.uuid, uuid, sizeof(cmd.uuid));
+       memset(cmd.name, 0, sizeof(cmd.name));
+       memcpy(cmd.name, service_name, strlen(service_name));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_LISTEN,
+                               sizeof(cmd), &cmd, NULL, NULL, sock);
+}
+
+static bt_status_t sock_listen(btsock_type_t type, const char *service_name,
+                                       const uint8_t *uuid, int chan,
+                                       int *sock, int flags)
+{
+       if ((!uuid && chan <= 0) || !sock) {
+               error("Invalid params: uuid %s, chan %d, sock %p",
+                                               btuuid2str(uuid), chan, sock);
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       DBG("uuid %s chan %d sock %p type %d service_name %s",
+                       btuuid2str(uuid), chan, sock, type, service_name);
+
+       switch (type) {
+       case BTSOCK_RFCOMM:
+               return sock_listen_rfcomm(service_name, uuid, chan, sock,
+                                                                       flags);
+       default:
+               error("%s: Socket type %d not supported", __func__, type);
+               break;
+       }
+
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t sock_connect(const bt_bdaddr_t *bdaddr, btsock_type_t type,
+                                       const uint8_t *uuid, int chan,
+                                       int *sock, int flags)
+{
+       struct hal_cmd_sock_connect cmd;
+
+       if ((!uuid && chan <= 0) || !bdaddr || !sock) {
+               error("Invalid params: bd_addr %p, uuid %s, chan %d, sock %p",
+                                       bdaddr, btuuid2str(uuid), chan, sock);
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       DBG("uuid %s chan %d sock %p type %d", btuuid2str(uuid), chan, sock,
+                                                                       type);
+
+       if (type != BTSOCK_RFCOMM) {
+               error("Socket type %u not supported", type);
+               return BT_STATUS_UNSUPPORTED;
+       }
+
+       cmd.flags = flags;
+       cmd.type = type;
+       cmd.channel = chan;
+       memcpy(cmd.uuid, uuid, sizeof(cmd.uuid));
+       memcpy(cmd.bdaddr, bdaddr, sizeof(cmd.bdaddr));
+
+       return hal_ipc_cmd(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT,
+                                       sizeof(cmd), &cmd, NULL, NULL, sock);
+}
+
+static btsock_interface_t sock_if = {
+       sizeof(sock_if),
+       sock_listen,
+       sock_connect
+};
+
+btsock_interface_t *bt_get_sock_interface(void)
+{
+       return &sock_if;
+}
diff --git a/android/hal-utils.c b/android/hal-utils.c
new file mode 100644 (file)
index 0000000..4f44d98
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "hal-utils.h"
+
+/*
+ * converts uuid to string
+ * buf should be at least 39 bytes
+ *
+ * returns string representation of uuid
+ */
+const char *bt_uuid_t2str(const uint8_t *uuid, char *buf)
+{
+       int shift = 0;
+       unsigned int i;
+       int is_bt;
+
+       is_bt = !memcmp(&uuid[4], &BT_BASE_UUID[4], HAL_UUID_LEN - 4);
+
+       for (i = 0; i < HAL_UUID_LEN; i++) {
+               if (i == 4 && is_bt)
+                       break;
+
+               if (i == 4 || i == 6 || i == 8 || i == 10) {
+                       buf[i * 2 + shift] = '-';
+                       shift++;
+               }
+               sprintf(buf + i * 2 + shift, "%02x", uuid[i]);
+       }
+
+       return buf;
+}
+
+const char *btuuid2str(const uint8_t *uuid)
+{
+       static char buf[MAX_UUID_STR_LEN];
+
+       return bt_uuid_t2str(uuid, buf);
+}
+
+INTMAP(bt_status_t, -1, "(unknown)")
+       DELEMENT(BT_STATUS_SUCCESS),
+       DELEMENT(BT_STATUS_FAIL),
+       DELEMENT(BT_STATUS_NOT_READY),
+       DELEMENT(BT_STATUS_NOMEM),
+       DELEMENT(BT_STATUS_BUSY),
+       DELEMENT(BT_STATUS_DONE),
+       DELEMENT(BT_STATUS_UNSUPPORTED),
+       DELEMENT(BT_STATUS_PARM_INVALID),
+       DELEMENT(BT_STATUS_UNHANDLED),
+       DELEMENT(BT_STATUS_AUTH_FAILURE),
+       DELEMENT(BT_STATUS_RMT_DEV_DOWN),
+ENDMAP
+
+INTMAP(bt_state_t, -1, "(unknown)")
+       DELEMENT(BT_STATE_OFF),
+       DELEMENT(BT_STATE_ON),
+ENDMAP
+
+INTMAP(bt_device_type_t, -1, "(unknown)")
+       DELEMENT(BT_DEVICE_DEVTYPE_BREDR),
+       DELEMENT(BT_DEVICE_DEVTYPE_BLE),
+       DELEMENT(BT_DEVICE_DEVTYPE_DUAL),
+ENDMAP
+
+INTMAP(bt_scan_mode_t, -1, "(unknown)")
+       DELEMENT(BT_SCAN_MODE_NONE),
+       DELEMENT(BT_SCAN_MODE_CONNECTABLE),
+       DELEMENT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE),
+ENDMAP
+
+INTMAP(bt_discovery_state_t, -1, "(unknown)")
+       DELEMENT(BT_DISCOVERY_STOPPED),
+       DELEMENT(BT_DISCOVERY_STARTED),
+ENDMAP
+
+INTMAP(bt_acl_state_t, -1, "(unknown)")
+       DELEMENT(BT_ACL_STATE_CONNECTED),
+       DELEMENT(BT_ACL_STATE_DISCONNECTED),
+ENDMAP
+
+INTMAP(bt_bond_state_t, -1, "(unknown)")
+       DELEMENT(BT_BOND_STATE_NONE),
+       DELEMENT(BT_BOND_STATE_BONDING),
+       DELEMENT(BT_BOND_STATE_BONDED),
+ENDMAP
+
+INTMAP(bt_ssp_variant_t, -1, "(unknown)")
+       DELEMENT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+       DELEMENT(BT_SSP_VARIANT_PASSKEY_ENTRY),
+       DELEMENT(BT_SSP_VARIANT_CONSENT),
+       DELEMENT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION),
+ENDMAP
+
+INTMAP(bt_property_type_t, -1, "(unknown)")
+       DELEMENT(BT_PROPERTY_BDNAME),
+       DELEMENT(BT_PROPERTY_BDADDR),
+       DELEMENT(BT_PROPERTY_UUIDS),
+       DELEMENT(BT_PROPERTY_CLASS_OF_DEVICE),
+       DELEMENT(BT_PROPERTY_TYPE_OF_DEVICE),
+       DELEMENT(BT_PROPERTY_SERVICE_RECORD),
+       DELEMENT(BT_PROPERTY_ADAPTER_SCAN_MODE),
+       DELEMENT(BT_PROPERTY_ADAPTER_BONDED_DEVICES),
+       DELEMENT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT),
+       DELEMENT(BT_PROPERTY_REMOTE_FRIENDLY_NAME),
+       DELEMENT(BT_PROPERTY_REMOTE_RSSI),
+#if PLATFORM_SDK_VERSION > 17
+       DELEMENT(BT_PROPERTY_REMOTE_VERSION_INFO),
+#endif
+       DELEMENT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP),
+ENDMAP
+
+INTMAP(bt_cb_thread_evt, -1, "(unknown)")
+       DELEMENT(ASSOCIATE_JVM),
+       DELEMENT(DISASSOCIATE_JVM),
+ENDMAP
+
+/* Find first index of given value in table m */
+int int2str_findint(int v, const struct int2str m[])
+{
+       int i;
+
+       for (i = 0; m[i].str; ++i) {
+               if (m[i].val == v)
+                       return i;
+       }
+       return -1;
+}
+
+/* Find first index of given string in table m */
+int int2str_findstr(const char *str, const struct int2str m[])
+{
+       int i;
+
+       for (i = 0; m[i].str; ++i) {
+               if (strcmp(m[i].str, str) == 0)
+                       return i;
+       }
+       return -1;
+}
+
+/*
+ * convert bd_addr to string
+ * buf must be at least 18 char long
+ *
+ * returns buf
+ */
+const char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf)
+{
+       const uint8_t *p = bd_addr->address;
+
+       snprintf(buf, MAX_ADDR_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
+                                       p[0], p[1], p[2], p[3], p[4], p[5]);
+
+       return buf;
+}
+
+/* converts string to bt_bdaddr_t */
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr)
+{
+       uint8_t *p = bd_addr->address;
+
+       sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+                               &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]);
+}
+
+/* converts string to uuid */
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid)
+{
+       int i = 0;
+
+       memcpy(uuid, BT_BASE_UUID, sizeof(bt_uuid_t));
+
+       while (*str && i < (int) sizeof(bt_uuid_t)) {
+               while (*str == '-')
+                       str++;
+
+               if (sscanf(str, "%02hhx", &uuid->uu[i]) != 1)
+                       break;
+
+               i++;
+               str += 2;
+       }
+}
+
+const char *enum_defines(void *v, int i)
+{
+       const struct int2str *m = v;
+
+       return m[i].str != NULL ? m[i].str : NULL;
+}
+
+const char *enum_strings(void *v, int i)
+{
+       const char **m = v;
+
+       return m[i] != NULL ? m[i] : NULL;
+}
+
+const char *enum_one_string(void *v, int i)
+{
+       const char *m = v;
+
+       return (i == 0) && (m[0] != 0) ? m : NULL;
+}
+
+const char *bdaddr2str(const bt_bdaddr_t *bd_addr)
+{
+       static char buf[MAX_ADDR_STR_LEN];
+
+       return bt_bdaddr_t2str(bd_addr, buf);
+}
+
+const char *btproperty2str(const bt_property_t *property)
+{
+       static char buf[4096];
+       char *p;
+
+       p = buf + sprintf(buf, "type=%s len=%d val=",
+                                       bt_property_type_t2str(property->type),
+                                       property->len);
+
+       switch (property->type) {
+       case BT_PROPERTY_BDNAME:
+       case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+               snprintf(p, property->len + 1, "%s",
+                                       ((bt_bdname_t *) property->val)->name);
+               break;
+
+       case BT_PROPERTY_BDADDR:
+               sprintf(p, "%s", bdaddr2str((bt_bdaddr_t *) property->val));
+               break;
+
+       case BT_PROPERTY_CLASS_OF_DEVICE:
+               sprintf(p, "%06x", *((int *) property->val));
+               break;
+
+       case BT_PROPERTY_TYPE_OF_DEVICE:
+               sprintf(p, "%s", bt_device_type_t2str(
+                               *((bt_device_type_t *) property->val)));
+               break;
+
+       case BT_PROPERTY_REMOTE_RSSI:
+               sprintf(p, "%d", *((char *) property->val));
+               break;
+
+       case BT_PROPERTY_ADAPTER_SCAN_MODE:
+               sprintf(p, "%s",
+                       bt_scan_mode_t2str(*((bt_scan_mode_t *) property->val)));
+               break;
+
+       case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+               sprintf(p, "%d", *((int *) property->val));
+               break;
+
+       case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+               {
+                       int count = property->len / sizeof(bt_bdaddr_t);
+                       char *ptr = property->val;
+
+                       strcat(p, "{");
+
+                       while (count--) {
+                               strcat(p, bdaddr2str((bt_bdaddr_t *) ptr));
+                               if (count)
+                                       strcat(p, ", ");
+                               ptr += sizeof(bt_bdaddr_t);
+                       }
+
+                       strcat(p, "}");
+
+               }
+               break;
+
+       case BT_PROPERTY_UUIDS:
+               {
+                       int count = property->len / sizeof(bt_uuid_t);
+                       uint8_t *ptr = property->val;
+
+                       strcat(p, "{");
+
+                       while (count--) {
+                               strcat(p, btuuid2str(ptr));
+                               if (count)
+                                       strcat(p, ", ");
+                               ptr += sizeof(bt_uuid_t);
+                       }
+
+                       strcat(p, "}");
+
+               }
+               break;
+
+       case BT_PROPERTY_SERVICE_RECORD:
+               {
+                       bt_service_record_t *rec = property->val;
+
+                       sprintf(p, "{%s, %d, %s}", btuuid2str(rec->uuid.uu),
+                                               rec->channel, rec->name);
+               }
+               break;
+
+       default:
+               sprintf(p, "%p", property->val);
+       }
+
+       return buf;
+}
diff --git a/android/hal-utils.h b/android/hal-utils.h
new file mode 100644 (file)
index 0000000..75de7e9
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 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 <hardware/bluetooth.h>
+
+#define MAX_UUID_STR_LEN       37
+#define HAL_UUID_LEN           16
+#define MAX_ADDR_STR_LEN       18
+
+static const char BT_BASE_UUID[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+const char *bt_uuid_t2str(const uint8_t *uuid, char *buf);
+const char *btuuid2str(const uint8_t *uuid);
+const char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf);
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr);
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid);
+const char *btproperty2str(const bt_property_t *property);
+const char *bdaddr2str(const bt_bdaddr_t *bd_addr);
+
+/**
+ * Begin mapping section
+ *
+ * There are some mappings between integer values (enums) and strings
+ * to be presented to user. To make it easier to convert between those two
+ * set of macros is given. It is specially useful when we want to have
+ * strings that match constants from header files like:
+ *  BT_STATUS_SUCCESS (0) and corresponding "BT_STATUS_SUCCESS"
+ * Example of usage:
+ *
+ * INTMAP(int, -1, "invalid")
+ *   DELEMENT(BT_STATUS_SUCCESS)
+ *   DELEMENT(BT_STATUS_FAIL)
+ *   MELEMENT(123, "Some strange value")
+ * ENDMAP
+ *
+ * Just by doing this we have mapping table plus two functions:
+ *  int str2int(const char *str);
+ *  const char *int2str(int v);
+ *
+ * second argument to INTMAP specifies value to be returned from
+ * str2int function when there is not mapping for such number
+ * third argument specifies default value to be returned from int2str
+ *
+ * If same mapping is to be used in several source files put
+ * INTMAP in c file and DECINTMAP in h file.
+ *
+ * For mappings that are to be used in single file only
+ * use SINTMAP which will create the same but everything will be marked
+ * as static.
+ */
+
+struct int2str {
+       int val;                /* int value */
+       const char *str;        /* corresponding string */
+};
+
+int int2str_findint(int v, const struct int2str m[]);
+int int2str_findstr(const char *str, const struct int2str m[]);
+const char *enum_defines(void *v, int i);
+const char *enum_strings(void *v, int i);
+const char *enum_one_string(void *v, int i);
+
+#define TYPE_ENUM(type) ((void *) &__##type##2str[0])
+#define DECINTMAP(type) \
+extern struct int2str __##type##2str[]; \
+const char *type##2##str(type v); \
+type str##2##type(const char *str); \
+
+#define INTMAP(type, deft, defs) \
+const char *type##2##str(type v) \
+{ \
+       int i = int2str_findint((int) v, __##type##2str); \
+       return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+type str##2##type(const char *str) \
+{ \
+       int i = int2str_findstr(str, __##type##2str); \
+       return (i < 0) ? (type) deft : (type) (__##type##2str[i].val); \
+} \
+struct int2str __##type##2str[] = {
+
+#define SINTMAP(type, deft, defs) \
+static struct int2str __##type##2str[]; \
+static inline const char *type##2##str(type v) \
+{ \
+       int i = int2str_findint((int) v, __##type##2str); \
+       return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+static inline type str##2##type(const char *str) \
+{ \
+       int i = int2str_findstr(str, __##type##2str); \
+       return (i < 0) ? (type) deft : (type) (__##type##2str[i].val); \
+} \
+static struct int2str __##type##2str[] = {
+
+#define ENDMAP {0, NULL} };
+
+/* use this to generate string from header file constant */
+#define MELEMENT(v, s) {v, s}
+/* use this to have arbitrary mapping from int to string */
+#define DELEMENT(s) {s, #s}
+/* End of mapping section */
+
+DECINTMAP(bt_status_t);
+DECINTMAP(bt_state_t);
+DECINTMAP(bt_device_type_t);
+DECINTMAP(bt_scan_mode_t);
+DECINTMAP(bt_discovery_state_t);
+DECINTMAP(bt_acl_state_t);
+DECINTMAP(bt_bond_state_t);
+DECINTMAP(bt_ssp_variant_t);
+DECINTMAP(bt_property_type_t);
+DECINTMAP(bt_cb_thread_evt);
diff --git a/android/hal.h b/android/hal.h
new file mode 100644 (file)
index 0000000..72090fe
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 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 <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_av.h>
+
+btsock_interface_t *bt_get_sock_interface(void);
+bthh_interface_t *bt_get_hidhost_interface(void);
+btpan_interface_t *bt_get_pan_interface(void);
+btav_interface_t *bt_get_a2dp_interface(void);
+
+void bt_notify_adapter(uint8_t opcode, void *buf, uint16_t len);
+void bt_thread_associate(void);
+void bt_thread_disassociate(void);
+void bt_notify_hidhost(uint8_t opcode, void *buf, uint16_t len);
+void bt_notify_a2dp(uint8_t opcode, void *buf, uint16_t len);
+void bt_notify_pan(uint8_t opcode, void *buf, uint16_t len);
diff --git a/android/hardware/bluetooth.h b/android/hardware/bluetooth.h
new file mode 100644 (file)
index 0000000..c00a8f7
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BLUETOOTH_H
+#define ANDROID_INCLUDE_BLUETOOTH_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+/**
+ * The Bluetooth Hardware Module ID
+ */
+
+#define BT_HARDWARE_MODULE_ID "bluetooth"
+#define BT_STACK_MODULE_ID "bluetooth"
+#define BT_STACK_TEST_MODULE_ID "bluetooth_test"
+
+
+/* Bluetooth profile interface IDs */
+
+#define BT_PROFILE_HANDSFREE_ID "handsfree"
+#define BT_PROFILE_ADVANCED_AUDIO_ID "a2dp"
+#define BT_PROFILE_HEALTH_ID "health"
+#define BT_PROFILE_SOCKETS_ID "socket"
+#define BT_PROFILE_HIDHOST_ID "hidhost"
+#define BT_PROFILE_PAN_ID "pan"
+
+#define BT_PROFILE_GATT_ID "gatt"
+#define BT_PROFILE_AV_RC_ID "avrcp"
+
+/** Bluetooth Address */
+typedef struct {
+    uint8_t address[6];
+} __attribute__((packed))bt_bdaddr_t;
+
+/** Bluetooth Device Name */
+typedef struct {
+    uint8_t name[249];
+} __attribute__((packed))bt_bdname_t;
+
+/** Bluetooth Adapter Visibility Modes*/
+typedef enum {
+    BT_SCAN_MODE_NONE,
+    BT_SCAN_MODE_CONNECTABLE,
+    BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+} bt_scan_mode_t;
+
+/** Bluetooth Adapter State */
+typedef enum {
+    BT_STATE_OFF,
+    BT_STATE_ON
+}   bt_state_t;
+
+/** Bluetooth Error Status */
+/** We need to build on this */
+
+typedef enum {
+    BT_STATUS_SUCCESS,
+    BT_STATUS_FAIL,
+    BT_STATUS_NOT_READY,
+    BT_STATUS_NOMEM,
+    BT_STATUS_BUSY,
+    BT_STATUS_DONE,        /* request already completed */
+    BT_STATUS_UNSUPPORTED,
+    BT_STATUS_PARM_INVALID,
+    BT_STATUS_UNHANDLED,
+    BT_STATUS_AUTH_FAILURE,
+    BT_STATUS_RMT_DEV_DOWN
+
+} bt_status_t;
+
+/** Bluetooth PinKey Code */
+typedef struct {
+    uint8_t pin[16];
+} __attribute__((packed))bt_pin_code_t;
+
+/** Bluetooth Adapter Discovery state */
+typedef enum {
+    BT_DISCOVERY_STOPPED,
+    BT_DISCOVERY_STARTED
+} bt_discovery_state_t;
+
+/** Bluetooth ACL connection state */
+typedef enum {
+    BT_ACL_STATE_CONNECTED,
+    BT_ACL_STATE_DISCONNECTED
+} bt_acl_state_t;
+
+/** Bluetooth 128-bit UUID */
+typedef struct {
+   uint8_t uu[16];
+} bt_uuid_t;
+
+/** Bluetooth SDP service record */
+typedef struct
+{
+   bt_uuid_t uuid;
+   uint16_t channel;
+   char name[256]; // what's the maximum length
+} bt_service_record_t;
+
+
+/** Bluetooth Remote Version info */
+typedef struct
+{
+   int version;
+   int sub_ver;
+   int manufacturer;
+} bt_remote_version_t;
+
+/* Bluetooth Adapter and Remote Device property types */
+typedef enum {
+    /* Properties common to both adapter and remote device */
+    /**
+     * Description - Bluetooth Device Name
+     * Access mode - Adapter name can be GET/SET. Remote device can be GET
+     * Data type   - bt_bdname_t
+     */
+    BT_PROPERTY_BDNAME = 0x1,
+    /**
+     * Description - Bluetooth Device Address
+     * Access mode - Only GET.
+     * Data type   - bt_bdaddr_t
+     */
+    BT_PROPERTY_BDADDR,
+    /**
+     * Description - Bluetooth Service 128-bit UUIDs
+     * Access mode - Only GET.
+     * Data type   - Array of bt_uuid_t (Array size inferred from property length).
+     */
+    BT_PROPERTY_UUIDS,
+    /**
+     * Description - Bluetooth Class of Device as found in Assigned Numbers
+     * Access mode - Only GET.
+     * Data type   - uint32_t.
+     */
+    BT_PROPERTY_CLASS_OF_DEVICE,
+    /**
+     * Description - Device Type - BREDR, BLE or DUAL Mode
+     * Access mode - Only GET.
+     * Data type   - bt_device_type_t
+     */
+    BT_PROPERTY_TYPE_OF_DEVICE,
+    /**
+     * Description - Bluetooth Service Record
+     * Access mode - Only GET.
+     * Data type   - bt_service_record_t
+     */
+    BT_PROPERTY_SERVICE_RECORD,
+
+    /* Properties unique to adapter */
+    /**
+     * Description - Bluetooth Adapter scan mode
+     * Access mode - GET and SET
+     * Data type   - bt_scan_mode_t.
+     */
+    BT_PROPERTY_ADAPTER_SCAN_MODE,
+    /**
+     * Description - List of bonded devices
+     * Access mode - Only GET.
+     * Data type   - Array of bt_bdaddr_t of the bonded remote devices
+     *               (Array size inferred from property length).
+     */
+    BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+    /**
+     * Description - Bluetooth Adapter Discovery timeout (in seconds)
+     * Access mode - GET and SET
+     * Data type   - uint32_t
+     */
+    BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+
+    /* Properties unique to remote device */
+    /**
+     * Description - User defined friendly name of the remote device
+     * Access mode - GET and SET
+     * Data type   - bt_bdname_t.
+     */
+    BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+    /**
+     * Description - RSSI value of the inquired remote device
+     * Access mode - Only GET.
+     * Data type   - int32_t.
+     */
+    BT_PROPERTY_REMOTE_RSSI,
+    /**
+     * Description - Remote version info
+     * Access mode - SET/GET.
+     * Data type   - bt_remote_version_t.
+     */
+
+    BT_PROPERTY_REMOTE_VERSION_INFO,
+
+    BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
+} bt_property_type_t;
+
+/** Bluetooth Adapter Property data structure */
+typedef struct
+{
+    bt_property_type_t type;
+    int len;
+    void *val;
+} bt_property_t;
+
+/** Bluetooth Device Type */
+typedef enum {
+    BT_DEVICE_DEVTYPE_BREDR = 0x1,
+    BT_DEVICE_DEVTYPE_BLE,
+    BT_DEVICE_DEVTYPE_DUAL
+} bt_device_type_t;
+/** Bluetooth Bond state */
+typedef enum {
+    BT_BOND_STATE_NONE,
+    BT_BOND_STATE_BONDING,
+    BT_BOND_STATE_BONDED
+} bt_bond_state_t;
+
+/** Bluetooth SSP Bonding Variant */
+typedef enum {
+    BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
+    BT_SSP_VARIANT_PASSKEY_ENTRY,
+    BT_SSP_VARIANT_CONSENT,
+    BT_SSP_VARIANT_PASSKEY_NOTIFICATION
+} bt_ssp_variant_t;
+
+#define BT_MAX_NUM_UUIDS 32
+
+/** Bluetooth Interface callbacks */
+
+/** Bluetooth Enable/Disable Callback. */
+typedef void (*adapter_state_changed_callback)(bt_state_t state);
+
+/** GET/SET Adapter Properties callback */
+/* TODO: For the GET/SET property APIs/callbacks, we may need a session
+ * identifier to associate the call with the callback. This would be needed
+ * whenever more than one simultaneous instance of the same adapter_type
+ * is get/set.
+ *
+ * If this is going to be handled in the Java framework, then we do not need
+ * to manage sessions here.
+ */
+typedef void (*adapter_properties_callback)(bt_status_t status,
+                                               int num_properties,
+                                               bt_property_t *properties);
+
+/** GET/SET Remote Device Properties callback */
+/** TODO: For remote device properties, do not see a need to get/set
+ * multiple properties - num_properties shall be 1
+ */
+typedef void (*remote_device_properties_callback)(bt_status_t status,
+                                                       bt_bdaddr_t *bd_addr,
+                                                       int num_properties,
+                                                       bt_property_t *properties);
+
+/** New device discovered callback */
+/** If EIR data is not present, then BD_NAME and RSSI shall be NULL and -1
+ * respectively */
+typedef void (*device_found_callback)(int num_properties,
+                                         bt_property_t *properties);
+
+/** Discovery state changed callback */
+typedef void (*discovery_state_changed_callback)(bt_discovery_state_t state);
+
+/** Bluetooth Legacy PinKey Request callback */
+typedef void (*pin_request_callback)(bt_bdaddr_t *remote_bd_addr,
+                                        bt_bdname_t *bd_name, uint32_t cod);
+
+/** Bluetooth SSP Request callback - Just Works & Numeric Comparison*/
+/** pass_key - Shall be 0 for BT_SSP_PAIRING_VARIANT_CONSENT &
+ *  BT_SSP_PAIRING_PASSKEY_ENTRY */
+/* TODO: Passkey request callback shall not be needed for devices with display
+ * capability. We still need support this in the stack for completeness */
+typedef void (*ssp_request_callback)(bt_bdaddr_t *remote_bd_addr,
+                                        bt_bdname_t *bd_name,
+                                        uint32_t cod,
+                                        bt_ssp_variant_t pairing_variant,
+                                     uint32_t pass_key);
+
+/** Bluetooth Bond state changed callback */
+/* Invoked in response to create_bond, cancel_bond or remove_bond */
+typedef void (*bond_state_changed_callback)(bt_status_t status,
+                                               bt_bdaddr_t *remote_bd_addr,
+                                               bt_bond_state_t state);
+
+/** Bluetooth ACL connection state changed callback */
+typedef void (*acl_state_changed_callback)(bt_status_t status, bt_bdaddr_t *remote_bd_addr,
+                                            bt_acl_state_t state);
+
+typedef enum {
+    ASSOCIATE_JVM,
+    DISASSOCIATE_JVM
+} bt_cb_thread_evt;
+
+/** Thread Associate/Disassociate JVM Callback */
+/* Callback that is invoked by the callback thread to allow upper layer to attach/detach to/from
+ * the JVM */
+typedef void (*callback_thread_event)(bt_cb_thread_evt evt);
+
+/** Bluetooth Test Mode Callback */
+/* Receive any HCI event from controller. Must be in DUT Mode for this callback to be received */
+typedef void (*dut_mode_recv_callback)(uint16_t opcode, uint8_t *buf, uint8_t len);
+
+/* LE Test mode callbacks
+* This callback shall be invoked whenever the le_tx_test, le_rx_test or le_test_end is invoked
+* The num_packets is valid only for le_test_end command */
+typedef void (*le_test_mode_callback)(bt_status_t status, uint16_t num_packets);
+/** TODO: Add callbacks for Link Up/Down and other generic
+  *  notifications/callbacks */
+
+/** Bluetooth DM callback structure. */
+typedef struct {
+    /** set to sizeof(bt_callbacks_t) */
+    size_t size;
+    adapter_state_changed_callback adapter_state_changed_cb;
+    adapter_properties_callback adapter_properties_cb;
+    remote_device_properties_callback remote_device_properties_cb;
+    device_found_callback device_found_cb;
+    discovery_state_changed_callback discovery_state_changed_cb;
+    pin_request_callback pin_request_cb;
+    ssp_request_callback ssp_request_cb;
+    bond_state_changed_callback bond_state_changed_cb;
+    acl_state_changed_callback acl_state_changed_cb;
+    callback_thread_event thread_evt_cb;
+    dut_mode_recv_callback dut_mode_recv_cb;
+    le_test_mode_callback le_test_mode_cb;
+} bt_callbacks_t;
+
+/** NOTE: By default, no profiles are initialized at the time of init/enable.
+ *  Whenever the application invokes the 'init' API of a profile, then one of
+ *  the following shall occur:
+ *
+ *    1.) If Bluetooth is not enabled, then the Bluetooth core shall mark the
+ *        profile as enabled. Subsequently, when the application invokes the
+ *        Bluetooth 'enable', as part of the enable sequence the profile that were
+ *        marked shall be enabled by calling appropriate stack APIs. The
+ *        'adapter_properties_cb' shall return the list of UUIDs of the
+ *        enabled profiles.
+ *
+ *    2.) If Bluetooth is enabled, then the Bluetooth core shall invoke the stack
+ *        profile API to initialize the profile and trigger a
+ *        'adapter_properties_cb' with the current list of UUIDs including the
+ *        newly added profile's UUID.
+ *
+ *   The reverse shall occur whenever the profile 'cleanup' APIs are invoked
+ */
+
+/** Represents the standard Bluetooth DM interface. */
+typedef struct {
+    /** set to sizeof(bt_interface_t) */
+    size_t size;
+    /**
+     * Opens the interface and provides the callback routines
+     * to the implemenation of this interface.
+     */
+    int (*init)(bt_callbacks_t* callbacks );
+
+    /** Enable Bluetooth. */
+    int (*enable)(void);
+
+    /** Disable Bluetooth. */
+    int (*disable)(void);
+
+    /** Closes the interface. */
+    void (*cleanup)(void);
+
+    /** Get all Bluetooth Adapter properties at init */
+    int (*get_adapter_properties)(void);
+
+    /** Get Bluetooth Adapter property of 'type' */
+    int (*get_adapter_property)(bt_property_type_t type);
+
+    /** Set Bluetooth Adapter property of 'type' */
+    /* Based on the type, val shall be one of
+     * bt_bdaddr_t or bt_bdname_t or bt_scanmode_t etc
+     */
+    int (*set_adapter_property)(const bt_property_t *property);
+
+    /** Get all Remote Device properties */
+    int (*get_remote_device_properties)(bt_bdaddr_t *remote_addr);
+
+    /** Get Remote Device property of 'type' */
+    int (*get_remote_device_property)(bt_bdaddr_t *remote_addr,
+                                      bt_property_type_t type);
+
+    /** Set Remote Device property of 'type' */
+    int (*set_remote_device_property)(bt_bdaddr_t *remote_addr,
+                                      const bt_property_t *property);
+
+    /** Get Remote Device's service record  for the given UUID */
+    int (*get_remote_service_record)(bt_bdaddr_t *remote_addr,
+                                     bt_uuid_t *uuid);
+
+    /** Start SDP to get remote services */
+    int (*get_remote_services)(bt_bdaddr_t *remote_addr);
+
+    /** Start Discovery */
+    int (*start_discovery)(void);
+
+    /** Cancel Discovery */
+    int (*cancel_discovery)(void);
+
+    /** Create Bluetooth Bonding */
+    int (*create_bond)(const bt_bdaddr_t *bd_addr);
+
+    /** Remove Bond */
+    int (*remove_bond)(const bt_bdaddr_t *bd_addr);
+
+    /** Cancel Bond */
+    int (*cancel_bond)(const bt_bdaddr_t *bd_addr);
+
+    /** BT Legacy PinKey Reply */
+    /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */
+    int (*pin_reply)(const bt_bdaddr_t *bd_addr, uint8_t accept,
+                     uint8_t pin_len, bt_pin_code_t *pin_code);
+
+    /** BT SSP Reply - Just Works, Numeric Comparison and Passkey
+     * passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON &
+     * BT_SSP_VARIANT_CONSENT
+     * For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey
+     * shall be zero */
+    int (*ssp_reply)(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
+                     uint8_t accept, uint32_t passkey);
+
+    /** Get Bluetooth profile interface */
+    const void* (*get_profile_interface) (const char *profile_id);
+
+    /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */
+    /* Configure DUT Mode - Use this mode to enter/exit DUT mode */
+    int (*dut_mode_configure)(uint8_t enable);
+
+    /* Send any test HCI (vendor-specific) command to the controller. Must be in DUT Mode */
+    int (*dut_mode_send)(uint16_t opcode, uint8_t *buf, uint8_t len);
+    /** BLE Test Mode APIs */
+    /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */
+    int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len);
+
+    /* enable or disable bluetooth HCI snoop log */
+    int (*config_hci_snoop_log)(uint8_t enable);
+} bt_interface_t;
+
+/** TODO: Need to add APIs for Service Discovery, Service authorization and
+  *       connection management. Also need to add APIs for configuring
+  *       properties of remote bonded devices such as name, UUID etc. */
+
+typedef struct {
+    struct hw_device_t common;
+    const bt_interface_t* (*get_bluetooth_interface)();
+} bluetooth_device_t;
+
+typedef bluetooth_device_t bluetooth_module_t;
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BLUETOOTH_H */
diff --git a/android/hardware/bt_av.h b/android/hardware/bt_av.h
new file mode 100644 (file)
index 0000000..2ec00c3
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_AV_H
+#define ANDROID_INCLUDE_BT_AV_H
+
+__BEGIN_DECLS
+
+/* Bluetooth AV connection states */
+typedef enum {
+    BTAV_CONNECTION_STATE_DISCONNECTED = 0,
+    BTAV_CONNECTION_STATE_CONNECTING,
+    BTAV_CONNECTION_STATE_CONNECTED,
+    BTAV_CONNECTION_STATE_DISCONNECTING
+} btav_connection_state_t;
+
+/* Bluetooth AV datapath states */
+typedef enum {
+    BTAV_AUDIO_STATE_REMOTE_SUSPEND = 0,
+    BTAV_AUDIO_STATE_STOPPED,
+    BTAV_AUDIO_STATE_STARTED,
+} btav_audio_state_t;
+
+
+/** Callback for connection state change.
+ *  state will have one of the values from btav_connection_state_t
+ */
+typedef void (* btav_connection_state_callback)(btav_connection_state_t state, 
+                                                    bt_bdaddr_t *bd_addr);
+
+/** Callback for audiopath state change.
+ *  state will have one of the values from btav_audio_state_t
+ */
+typedef void (* btav_audio_state_callback)(btav_audio_state_t state, 
+                                               bt_bdaddr_t *bd_addr);
+
+/** BT-AV callback structure. */
+typedef struct {
+    /** set to sizeof(btav_callbacks_t) */
+    size_t      size;
+    btav_connection_state_callback  connection_state_cb;
+    btav_audio_state_callback audio_state_cb;
+} btav_callbacks_t;
+
+/** 
+ * NOTE:
+ *
+ * 1. AVRCP 1.0 shall be supported initially. AVRCP passthrough commands
+ *    shall be handled internally via uinput 
+ *
+ * 2. A2DP data path shall be handled via a socket pipe between the AudioFlinger
+ *    android_audio_hw library and the Bluetooth stack.
+ * 
+ */
+/** Represents the standard BT-AV interface. */
+typedef struct {
+
+    /** set to sizeof(btav_interface_t) */
+    size_t          size;
+    /**
+     * Register the BtAv callbacks
+     */
+    bt_status_t (*init)( btav_callbacks_t* callbacks );
+
+    /** connect to headset */
+    bt_status_t (*connect)( bt_bdaddr_t *bd_addr );
+
+    /** dis-connect from headset */
+    bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );
+
+    /** Closes the interface. */
+    void  (*cleanup)( void );
+} btav_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_AV_H */
diff --git a/android/hardware/bt_gatt.h b/android/hardware/bt_gatt.h
new file mode 100644 (file)
index 0000000..42e14c2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_INCLUDE_BT_GATT_H
+#define ANDROID_INCLUDE_BT_GATT_H
+
+#include <stdint.h>
+#include "bt_gatt_client.h"
+#include "bt_gatt_server.h"
+
+__BEGIN_DECLS
+
+/** BT-GATT callbacks */
+typedef struct {
+    /** Set to sizeof(btgatt_callbacks_t) */
+    size_t size;
+
+    /** GATT Client callbacks */
+    const btgatt_client_callbacks_t* client;
+
+    /** GATT Server callbacks */
+    const btgatt_server_callbacks_t* server;
+} btgatt_callbacks_t;
+
+/** Represents the standard Bluetooth GATT interface. */
+typedef struct {
+    /** Set to sizeof(btgatt_interface_t) */
+    size_t          size;
+
+    /**
+     * Initializes the interface and provides callback routines
+     */
+    bt_status_t (*init)( const btgatt_callbacks_t* callbacks );
+
+    /** Closes the interface */
+    void (*cleanup)( void );
+
+    /** Pointer to the GATT client interface methods.*/
+    const btgatt_client_interface_t* client;
+
+    /** Pointer to the GATT server interface methods.*/
+    const btgatt_server_interface_t* server;
+} btgatt_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_H */
diff --git a/android/hardware/bt_gatt_client.h b/android/hardware/bt_gatt_client.h
new file mode 100644 (file)
index 0000000..d6b0cb4
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_INCLUDE_BT_GATT_CLIENT_H
+#define ANDROID_INCLUDE_BT_GATT_CLIENT_H
+
+#include <stdint.h>
+#include "bt_gatt_types.h"
+
+__BEGIN_DECLS
+
+/**
+ * Buffer sizes for maximum attribute length and maximum read/write
+ * operation buffer size.
+ */
+#define BTGATT_MAX_ATTR_LEN 600
+
+/** Buffer type for unformatted reads/writes */
+typedef struct
+{
+    uint8_t             value[BTGATT_MAX_ATTR_LEN];
+    uint16_t            len;
+} btgatt_unformatted_value_t;
+
+/** Parameters for GATT read operations */
+typedef struct
+{
+    btgatt_srvc_id_t    srvc_id;
+    btgatt_gatt_id_t    char_id;
+    btgatt_gatt_id_t    descr_id;
+    btgatt_unformatted_value_t value;
+    uint16_t            value_type;
+    uint8_t             status;
+} btgatt_read_params_t;
+
+/** Parameters for GATT write operations */
+typedef struct
+{
+    btgatt_srvc_id_t    srvc_id;
+    btgatt_gatt_id_t    char_id;
+    btgatt_gatt_id_t    descr_id;
+    uint8_t             status;
+} btgatt_write_params_t;
+
+/** Attribute change notification parameters */
+typedef struct
+{
+    uint8_t             value[BTGATT_MAX_ATTR_LEN];
+    bt_bdaddr_t         bda;
+    btgatt_srvc_id_t    srvc_id;
+    btgatt_gatt_id_t    char_id;
+    uint16_t            len;
+    uint8_t             is_notify;
+} btgatt_notify_params_t;
+
+typedef struct
+{
+    bt_bdaddr_t        *bda1;
+    bt_uuid_t          *uuid1;
+    uint16_t            u1;
+    uint16_t            u2;
+    uint16_t            u3;
+    uint16_t            u4;
+    uint16_t            u5;
+} btgatt_test_params_t;
+
+/** BT-GATT Client callback structure. */
+
+/** Callback invoked in response to register_client */
+typedef void (*register_client_callback)(int status, int client_if,
+                bt_uuid_t *app_uuid);
+
+/** Callback for scan results */
+typedef void (*scan_result_callback)(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data);
+
+/** GATT open callback invoked in response to open */
+typedef void (*connect_callback)(int conn_id, int status, int client_if, bt_bdaddr_t* bda);
+
+/** Callback invoked in response to close */
+typedef void (*disconnect_callback)(int conn_id, int status,
+                int client_if, bt_bdaddr_t* bda);
+
+/**
+ * Invoked in response to search_service when the GATT service search
+ * has been completed.
+ */
+typedef void (*search_complete_callback)(int conn_id, int status);
+
+/** Reports GATT services on a remote device */
+typedef void (*search_result_callback)( int conn_id, btgatt_srvc_id_t *srvc_id);
+
+/** GATT characteristic enumeration result callback */
+typedef void (*get_characteristic_callback)(int conn_id, int status,
+                btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                int char_prop);
+
+/** GATT descriptor enumeration result callback */
+typedef void (*get_descriptor_callback)(int conn_id, int status,
+                btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                btgatt_gatt_id_t *descr_id);
+
+/** GATT included service enumeration result callback */
+typedef void (*get_included_service_callback)(int conn_id, int status,
+                btgatt_srvc_id_t *srvc_id, btgatt_srvc_id_t *incl_srvc_id);
+
+/** Callback invoked in response to [de]register_for_notification */
+typedef void (*register_for_notification_callback)(int conn_id,
+                int registered, int status, btgatt_srvc_id_t *srvc_id,
+                btgatt_gatt_id_t *char_id);
+
+/**
+ * Remote device notification callback, invoked when a remote device sends
+ * a notification or indication that a client has registered for.
+ */
+typedef void (*notify_callback)(int conn_id, btgatt_notify_params_t *p_data);
+
+/** Reports result of a GATT read operation */
+typedef void (*read_characteristic_callback)(int conn_id, int status,
+                btgatt_read_params_t *p_data);
+
+/** GATT write characteristic operation callback */
+typedef void (*write_characteristic_callback)(int conn_id, int status,
+                btgatt_write_params_t *p_data);
+
+/** GATT execute prepared write callback */
+typedef void (*execute_write_callback)(int conn_id, int status);
+
+/** Callback invoked in response to read_descriptor */
+typedef void (*read_descriptor_callback)(int conn_id, int status,
+                btgatt_read_params_t *p_data);
+
+/** Callback invoked in response to write_descriptor */
+typedef void (*write_descriptor_callback)(int conn_id, int status,
+                btgatt_write_params_t *p_data);
+
+/** Callback triggered in response to read_remote_rssi */
+typedef void (*read_remote_rssi_callback)(int client_if, bt_bdaddr_t* bda,
+                                          int rssi, int status);
+
+/**
+ * Callback indicationg the status of a listen() operation
+ */
+typedef void (*listen_callback)(int status, int server_if);
+
+typedef struct {
+    register_client_callback            register_client_cb;
+    scan_result_callback                scan_result_cb;
+    connect_callback                    open_cb;
+    disconnect_callback                 close_cb;
+    search_complete_callback            search_complete_cb;
+    search_result_callback              search_result_cb;
+    get_characteristic_callback         get_characteristic_cb;
+    get_descriptor_callback             get_descriptor_cb;
+    get_included_service_callback       get_included_service_cb;
+    register_for_notification_callback  register_for_notification_cb;
+    notify_callback                     notify_cb;
+    read_characteristic_callback        read_characteristic_cb;
+    write_characteristic_callback       write_characteristic_cb;
+    read_descriptor_callback            read_descriptor_cb;
+    write_descriptor_callback           write_descriptor_cb;
+    execute_write_callback              execute_write_cb;
+    read_remote_rssi_callback           read_remote_rssi_cb;
+    listen_callback                     listen_cb;
+} btgatt_client_callbacks_t;
+
+/** Represents the standard BT-GATT client interface. */
+
+typedef struct {
+    /** Registers a GATT client application with the stack */
+    bt_status_t (*register_client)( bt_uuid_t *uuid );
+
+    /** Unregister a client application from the stack */
+    bt_status_t (*unregister_client)(int client_if );
+
+    /** Start or stop LE device scanning */
+    bt_status_t (*scan)( int client_if, bool start );
+
+    /** Create a connection to a remote LE or dual-mode device */
+    bt_status_t (*connect)( int client_if, const bt_bdaddr_t *bd_addr,
+                         bool is_direct );
+
+    /** Disconnect a remote device or cancel a pending connection */
+    bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
+                    int conn_id);
+
+    /** Start or stop advertisements to listen for incoming connections */
+    bt_status_t (*listen)(int client_if, bool start);
+
+    /** Clear the attribute cache for a given device */
+    bt_status_t (*refresh)( int client_if, const bt_bdaddr_t *bd_addr );
+
+    /**
+     * Enumerate all GATT services on a connected device.
+     * Optionally, the results can be filtered for a given UUID.
+     */
+    bt_status_t (*search_service)(int conn_id, bt_uuid_t *filter_uuid );
+
+    /**
+     * Enumerate included services for a given service.
+     * Set start_incl_srvc_id to NULL to get the first included service.
+     */
+    bt_status_t (*get_included_service)( int conn_id, btgatt_srvc_id_t *srvc_id,
+                                         btgatt_srvc_id_t *start_incl_srvc_id);
+
+    /**
+     * Enumerate characteristics for a given service.
+     * Set start_char_id to NULL to get the first characteristic.
+     */
+    bt_status_t (*get_characteristic)( int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id);
+
+    /**
+     * Enumerate descriptors for a given characteristic.
+     * Set start_descr_id to NULL to get the first descriptor.
+     */
+    bt_status_t (*get_descriptor)( int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                    btgatt_gatt_id_t *start_descr_id);
+
+    /** Read a characteristic on a remote device */
+    bt_status_t (*read_characteristic)( int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                    int auth_req );
+
+    /** Write a remote characteristic */
+    bt_status_t (*write_characteristic)(int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                    int write_type, int len, int auth_req,
+                    char* p_value);
+
+    /** Read the descriptor for a given characteristic */
+    bt_status_t (*read_descriptor)(int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                    btgatt_gatt_id_t *descr_id, int auth_req);
+
+    /** Write a remote descriptor for a given characteristic */
+    bt_status_t (*write_descriptor)( int conn_id,
+                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+                    btgatt_gatt_id_t *descr_id, int write_type, int len,
+                    int auth_req, char* p_value);
+
+    /** Execute a prepared write operation */
+    bt_status_t (*execute_write)(int conn_id, int execute);
+
+    /**
+     * Register to receive notifications or indications for a given
+     * characteristic
+     */
+    bt_status_t (*register_for_notification)( int client_if,
+                    const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+                    btgatt_gatt_id_t *char_id);
+
+    /** Deregister a previous request for notifications/indications */
+    bt_status_t (*deregister_for_notification)( int client_if,
+                    const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+                    btgatt_gatt_id_t *char_id);
+
+    /** Request RSSI for a given remote device */
+    bt_status_t (*read_remote_rssi)( int client_if, const bt_bdaddr_t *bd_addr);
+
+    /** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
+    int (*get_device_type)( const bt_bdaddr_t *bd_addr );
+
+    /** Set the advertising data or scan response data */
+    bt_status_t (*set_adv_data)(int server_if, bool set_scan_rsp, bool include_name,
+                    bool include_txpower, int min_interval, int max_interval, int appearance,
+                    uint16_t manufacturer_len, char* manufacturer_data);
+
+    /** Test mode interface */
+    bt_status_t (*test_command)( int command, btgatt_test_params_t* params);
+} btgatt_client_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_CLIENT_H */
diff --git a/android/hardware/bt_gatt_server.h b/android/hardware/bt_gatt_server.h
new file mode 100644 (file)
index 0000000..1a5a400
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_INCLUDE_BT_GATT_SERVER_H
+#define ANDROID_INCLUDE_BT_GATT_SERVER_H
+
+#include <stdint.h>
+
+#include "bt_gatt_types.h"
+
+__BEGIN_DECLS
+
+/** GATT value type used in response to remote read requests */
+typedef struct
+{
+    uint8_t           value[BTGATT_MAX_ATTR_LEN];
+    uint16_t          handle;
+    uint16_t          offset;
+    uint16_t          len;
+    uint8_t           auth_req;
+} btgatt_value_t;
+
+/** GATT remote read request response type */
+typedef union
+{
+    btgatt_value_t attr_value;
+    uint16_t            handle;
+} btgatt_response_t;
+
+/** BT-GATT Server callback structure. */
+
+/** Callback invoked in response to register_server */
+typedef void (*register_server_callback)(int status, int server_if,
+                bt_uuid_t *app_uuid);
+
+/** Callback indicating that a remote device has connected or been disconnected */
+typedef void (*connection_callback)(int conn_id, int server_if, int connected,
+                                    bt_bdaddr_t *bda);
+
+/** Callback invoked in response to create_service */
+typedef void (*service_added_callback)(int status, int server_if,
+                btgatt_srvc_id_t *srvc_id, int srvc_handle);
+
+/** Callback indicating that an included service has been added to a service */
+typedef void (*included_service_added_callback)(int status, int server_if,
+                int srvc_handle, int incl_srvc_handle);
+
+/** Callback invoked when a characteristic has been added to a service */
+typedef void (*characteristic_added_callback)(int status, int server_if,
+                bt_uuid_t *uuid, int srvc_handle, int char_handle);
+
+/** Callback invoked when a descriptor has been added to a characteristic */
+typedef void (*descriptor_added_callback)(int status, int server_if,
+                bt_uuid_t *uuid, int srvc_handle, int descr_handle);
+
+/** Callback invoked in response to start_service */
+typedef void (*service_started_callback)(int status, int server_if,
+                                         int srvc_handle);
+
+/** Callback invoked in response to stop_service */
+typedef void (*service_stopped_callback)(int status, int server_if,
+                                         int srvc_handle);
+
+/** Callback triggered when a service has been deleted */
+typedef void (*service_deleted_callback)(int status, int server_if,
+                                         int srvc_handle);
+
+/**
+ * Callback invoked when a remote device has requested to read a characteristic
+ * or descriptor. The application must respond by calling send_response
+ */
+typedef void (*request_read_callback)(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                                      int attr_handle, int offset, bool is_long);
+
+/**
+ * Callback invoked when a remote device has requested to write to a
+ * characteristic or descriptor.
+ */
+typedef void (*request_write_callback)(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                                       int attr_handle, int offset, int length,
+                                       bool need_rsp, bool is_prep, uint8_t* value);
+
+/** Callback invoked when a previously prepared write is to be executed */
+typedef void (*request_exec_write_callback)(int conn_id, int trans_id,
+                                            bt_bdaddr_t *bda, int exec_write);
+
+/**
+ * Callback triggered in response to send_response if the remote device
+ * sends a confirmation.
+ */
+typedef void (*response_confirmation_callback)(int status, int handle);
+
+typedef struct {
+    register_server_callback        register_server_cb;
+    connection_callback             connection_cb;
+    service_added_callback          service_added_cb;
+    included_service_added_callback included_service_added_cb;
+    characteristic_added_callback   characteristic_added_cb;
+    descriptor_added_callback       descriptor_added_cb;
+    service_started_callback        service_started_cb;
+    service_stopped_callback        service_stopped_cb;
+    service_deleted_callback        service_deleted_cb;
+    request_read_callback           request_read_cb;
+    request_write_callback          request_write_cb;
+    request_exec_write_callback     request_exec_write_cb;
+    response_confirmation_callback  response_confirmation_cb;
+} btgatt_server_callbacks_t;
+
+/** Represents the standard BT-GATT server interface. */
+typedef struct {
+    /** Registers a GATT server application with the stack */
+    bt_status_t (*register_server)( bt_uuid_t *uuid );
+
+    /** Unregister a server application from the stack */
+    bt_status_t (*unregister_server)(int server_if );
+
+    /** Create a connection to a remote peripheral */
+    bt_status_t (*connect)(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct );
+
+    /** Disconnect an established connection or cancel a pending one */
+    bt_status_t (*disconnect)(int server_if, const bt_bdaddr_t *bd_addr,
+                    int conn_id );
+
+    /** Create a new service */
+    bt_status_t (*add_service)( int server_if, btgatt_srvc_id_t *srvc_id, int num_handles);
+
+    /** Assign an included service to it's parent service */
+    bt_status_t (*add_included_service)( int server_if, int service_handle, int included_handle);
+
+    /** Add a characteristic to a service */
+    bt_status_t (*add_characteristic)( int server_if,
+                    int service_handle, bt_uuid_t *uuid,
+                    int properties, int permissions);
+
+    /** Add a descriptor to a given service */
+    bt_status_t (*add_descriptor)(int server_if, int service_handle,
+                                  bt_uuid_t *uuid, int permissions);
+
+    /** Starts a local service */
+    bt_status_t (*start_service)(int server_if, int service_handle,
+                                 int transport);
+
+    /** Stops a local service */
+    bt_status_t (*stop_service)(int server_if, int service_handle);
+
+    /** Delete a local service */
+    bt_status_t (*delete_service)(int server_if, int service_handle);
+
+    /** Send value indication to a remote device */
+    bt_status_t (*send_indication)(int server_if, int attribute_handle,
+                                   int conn_id, int len, int confirm,
+                                   char* p_value);
+
+    /** Send a response to a read/write operation */
+    bt_status_t (*send_response)(int conn_id, int trans_id,
+                                 int status, btgatt_response_t *response);
+} btgatt_server_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_CLIENT_H */
diff --git a/android/hardware/bt_gatt_types.h b/android/hardware/bt_gatt_types.h
new file mode 100644 (file)
index 0000000..0ac217e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_INCLUDE_BT_GATT_TYPES_H
+#define ANDROID_INCLUDE_BT_GATT_TYPES_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+/**
+ * GATT Service types
+ */
+#define BTGATT_SERVICE_TYPE_PRIMARY 0
+#define BTGATT_SERVICE_TYPE_SECONDARY 1
+
+/** GATT ID adding instance id tracking to the UUID */
+typedef struct
+{
+    bt_uuid_t           uuid;
+    uint8_t             inst_id;
+} btgatt_gatt_id_t;
+
+/** GATT Service ID also identifies the service type (primary/secondary) */
+typedef struct
+{
+    btgatt_gatt_id_t    id;
+    uint8_t             is_primary;
+} btgatt_srvc_id_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_TYPES_H */
diff --git a/android/hardware/bt_hf.h b/android/hardware/bt_hf.h
new file mode 100644 (file)
index 0000000..6135ac4
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HF_H
+#define ANDROID_INCLUDE_BT_HF_H
+
+__BEGIN_DECLS
+
+/* AT response code - OK/Error */
+typedef enum {
+    BTHF_AT_RESPONSE_ERROR = 0,
+    BTHF_AT_RESPONSE_OK
+} bthf_at_response_t;
+
+typedef enum {
+    BTHF_CONNECTION_STATE_DISCONNECTED = 0,
+    BTHF_CONNECTION_STATE_CONNECTING,
+    BTHF_CONNECTION_STATE_CONNECTED,
+    BTHF_CONNECTION_STATE_SLC_CONNECTED,
+    BTHF_CONNECTION_STATE_DISCONNECTING
+} bthf_connection_state_t;
+
+typedef enum {
+    BTHF_AUDIO_STATE_DISCONNECTED = 0,
+    BTHF_AUDIO_STATE_CONNECTING,
+    BTHF_AUDIO_STATE_CONNECTED,
+    BTHF_AUDIO_STATE_DISCONNECTING
+} bthf_audio_state_t;
+
+typedef enum {
+    BTHF_VR_STATE_STOPPED = 0,
+    BTHF_VR_STATE_STARTED
+} bthf_vr_state_t;
+
+typedef enum {
+    BTHF_VOLUME_TYPE_SPK = 0,
+    BTHF_VOLUME_TYPE_MIC
+} bthf_volume_type_t;
+
+/* Noise Reduction and Echo Cancellation */
+typedef enum
+{
+    BTHF_NREC_STOP,
+    BTHF_NREC_START
+} bthf_nrec_t;
+
+/* CHLD - Call held handling */
+typedef enum
+{
+    BTHF_CHLD_TYPE_RELEASEHELD,              // Terminate all held or set UDUB("busy") to a waiting call
+    BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD, // Terminate all active calls and accepts a waiting/held call
+    BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD,    // Hold all active calls and accepts a waiting/held call
+    BTHF_CHLD_TYPE_ADDHELDTOCONF,            // Add all held calls to a conference
+} bthf_chld_type_t;
+
+/** Callback for connection state change.
+ *  state will have one of the values from BtHfConnectionState
+ */
+typedef void (* bthf_connection_state_callback)(bthf_connection_state_t state, bt_bdaddr_t *bd_addr);
+
+/** Callback for audio connection state change.
+ *  state will have one of the values from BtHfAudioState
+ */
+typedef void (* bthf_audio_state_callback)(bthf_audio_state_t state, bt_bdaddr_t *bd_addr);
+
+/** Callback for VR connection state change.
+ *  state will have one of the values from BtHfVRState
+ */
+typedef void (* bthf_vr_cmd_callback)(bthf_vr_state_t state);
+
+/** Callback for answer incoming call (ATA)
+ */
+typedef void (* bthf_answer_call_cmd_callback)();
+
+/** Callback for disconnect call (AT+CHUP)
+ */
+typedef void (* bthf_hangup_call_cmd_callback)();
+
+/** Callback for disconnect call (AT+CHUP)
+ *  type will denote Speaker/Mic gain (BtHfVolumeControl).
+ */
+typedef void (* bthf_volume_cmd_callback)(bthf_volume_type_t type, int volume);
+
+/** Callback for dialing an outgoing call
+ *  If number is NULL, redial
+ */
+typedef void (* bthf_dial_call_cmd_callback)(char *number);
+
+/** Callback for sending DTMF tones
+ *  tone contains the dtmf character to be sent
+ */
+typedef void (* bthf_dtmf_cmd_callback)(char tone);
+
+/** Callback for enabling/disabling noise reduction/echo cancellation
+ *  value will be 1 to enable, 0 to disable
+ */
+typedef void (* bthf_nrec_cmd_callback)(bthf_nrec_t nrec);
+
+/** Callback for call hold handling (AT+CHLD)
+ *  value will contain the call hold command (0, 1, 2, 3)
+ */
+typedef void (* bthf_chld_cmd_callback)(bthf_chld_type_t chld);
+
+/** Callback for CNUM (subscriber number)
+ */
+typedef void (* bthf_cnum_cmd_callback)();
+
+/** Callback for indicators (CIND)
+ */
+typedef void (* bthf_cind_cmd_callback)();
+
+/** Callback for operator selection (COPS)
+ */
+typedef void (* bthf_cops_cmd_callback)();
+
+/** Callback for call list (AT+CLCC)
+ */
+typedef void (* bthf_clcc_cmd_callback) ();
+
+/** Callback for unknown AT command recd from HF
+ *  at_string will contain the unparsed AT string
+ */
+typedef void (* bthf_unknown_at_cmd_callback)(char *at_string);
+
+/** Callback for keypressed (HSP) event.
+ */
+typedef void (* bthf_key_pressed_cmd_callback)();
+
+/** BT-HF callback structure. */
+typedef struct {
+    /** set to sizeof(BtHfCallbacks) */
+    size_t      size;
+    bthf_connection_state_callback  connection_state_cb;
+    bthf_audio_state_callback       audio_state_cb;
+    bthf_vr_cmd_callback            vr_cmd_cb;
+    bthf_answer_call_cmd_callback   answer_call_cmd_cb;
+    bthf_hangup_call_cmd_callback   hangup_call_cmd_cb;
+    bthf_volume_cmd_callback        volume_cmd_cb;
+    bthf_dial_call_cmd_callback     dial_call_cmd_cb;
+    bthf_dtmf_cmd_callback          dtmf_cmd_cb;
+    bthf_nrec_cmd_callback          nrec_cmd_cb;
+    bthf_chld_cmd_callback          chld_cmd_cb;
+    bthf_cnum_cmd_callback          cnum_cmd_cb;
+    bthf_cind_cmd_callback          cind_cmd_cb;
+    bthf_cops_cmd_callback          cops_cmd_cb;
+    bthf_clcc_cmd_callback          clcc_cmd_cb;
+    bthf_unknown_at_cmd_callback    unknown_at_cmd_cb;
+    bthf_key_pressed_cmd_callback   key_pressed_cmd_cb;
+} bthf_callbacks_t;
+
+/** Network Status */
+typedef enum
+{
+    BTHF_NETWORK_STATE_NOT_AVAILABLE = 0,
+    BTHF_NETWORK_STATE_AVAILABLE
+} bthf_network_state_t;
+
+/** Service type */
+typedef enum
+{
+    BTHF_SERVICE_TYPE_HOME = 0,
+    BTHF_SERVICE_TYPE_ROAMING
+} bthf_service_type_t;
+
+typedef enum {
+    BTHF_CALL_STATE_ACTIVE = 0,
+    BTHF_CALL_STATE_HELD,
+    BTHF_CALL_STATE_DIALING,
+    BTHF_CALL_STATE_ALERTING,
+    BTHF_CALL_STATE_INCOMING,
+    BTHF_CALL_STATE_WAITING,
+    BTHF_CALL_STATE_IDLE
+} bthf_call_state_t;
+
+typedef enum {
+    BTHF_CALL_DIRECTION_OUTGOING = 0,
+    BTHF_CALL_DIRECTION_INCOMING
+} bthf_call_direction_t;
+
+typedef enum {
+    BTHF_CALL_TYPE_VOICE = 0,
+    BTHF_CALL_TYPE_DATA,
+    BTHF_CALL_TYPE_FAX
+} bthf_call_mode_t;
+
+typedef enum {
+    BTHF_CALL_MPTY_TYPE_SINGLE = 0,
+    BTHF_CALL_MPTY_TYPE_MULTI
+} bthf_call_mpty_type_t;
+
+typedef enum {
+    BTHF_CALL_ADDRTYPE_UNKNOWN = 0x81,
+    BTHF_CALL_ADDRTYPE_INTERNATIONAL = 0x91
+} bthf_call_addrtype_t;
+/** Represents the standard BT-HF interface. */
+typedef struct {
+
+    /** set to sizeof(BtHfInterface) */
+    size_t          size;
+    /**
+     * Register the BtHf callbacks
+     */
+    bt_status_t (*init)( bthf_callbacks_t* callbacks );
+
+    /** connect to headset */
+    bt_status_t (*connect)( bt_bdaddr_t *bd_addr );
+
+    /** dis-connect from headset */
+    bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );
+
+    /** create an audio connection */
+    bt_status_t (*connect_audio)( bt_bdaddr_t *bd_addr );
+
+    /** close the audio connection */
+    bt_status_t (*disconnect_audio)( bt_bdaddr_t *bd_addr );
+
+    /** start voice recognition */
+    bt_status_t (*start_voice_recognition)();
+
+    /** stop voice recognition */
+    bt_status_t (*stop_voice_recognition)();
+
+    /** volume control */
+    bt_status_t (*volume_control) (bthf_volume_type_t type, int volume);
+
+    /** Combined device status change notification */
+    bt_status_t (*device_status_notification)(bthf_network_state_t ntk_state, bthf_service_type_t svc_type, int signal,
+                           int batt_chg);
+
+    /** Response for COPS command */
+    bt_status_t (*cops_response)(const char *cops);
+
+    /** Response for CIND command */
+    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);
+
+    /** Pre-formatted AT response, typically in response to unknown AT cmd */
+    bt_status_t (*formatted_at_response)(const char *rsp);
+
+    /** ok/error response
+     *  ERROR (0)
+     *  OK    (1)
+     */
+    bt_status_t (*at_response) (bthf_at_response_t response_code, int error_code);
+
+    /** response for CLCC command 
+     *  Can be iteratively called for each call index
+     *  Call index of 0 will be treated as NULL termination (Completes response)
+     */
+    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);
+
+    /** notify of a call state change
+     *  Each update notifies 
+     *    1. Number of active/held/ringing calls
+     *    2. call_state: This denotes the state change that triggered this msg
+     *                   This will take one of the values from BtHfCallState
+     *    3. number & type: valid only for incoming & waiting call
+    */
+    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);
+
+    /** Closes the interface. */
+    void  (*cleanup)( void );
+} bthf_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HF_H */
diff --git a/android/hardware/bt_hh.h b/android/hardware/bt_hh.h
new file mode 100644 (file)
index 0000000..09f547b
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HH_H
+#define ANDROID_INCLUDE_BT_HH_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+#define BTHH_MAX_DSC_LEN   884
+
+/* HH connection states */
+typedef enum
+{
+    BTHH_CONN_STATE_CONNECTED              = 0,
+    BTHH_CONN_STATE_CONNECTING,
+    BTHH_CONN_STATE_DISCONNECTED,
+    BTHH_CONN_STATE_DISCONNECTING,
+    BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST,
+    BTHH_CONN_STATE_FAILED_KBD_FROM_HOST,
+    BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES,
+    BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER,
+    BTHH_CONN_STATE_FAILED_GENERIC,
+    BTHH_CONN_STATE_UNKNOWN
+} bthh_connection_state_t;
+
+typedef enum
+{
+    BTHH_OK                = 0,
+    BTHH_HS_HID_NOT_READY,        /* handshake error : device not ready */
+    BTHH_HS_INVALID_RPT_ID,       /* handshake error : invalid report ID */
+    BTHH_HS_TRANS_NOT_SPT,        /* handshake error : transaction not spt */
+    BTHH_HS_INVALID_PARAM,        /* handshake error : invalid paremter */
+    BTHH_HS_ERROR,                /* handshake error : unspecified HS error */
+    BTHH_ERR,                     /* general BTA HH error */
+    BTHH_ERR_SDP,                 /* SDP error */
+    BTHH_ERR_PROTO,               /* SET_Protocol error,
+                                                                only used in BTA_HH_OPEN_EVT callback */
+    BTHH_ERR_DB_FULL,             /* device database full error, used  */
+    BTHH_ERR_TOD_UNSPT,           /* type of device not supported */
+    BTHH_ERR_NO_RES,              /* out of system resources */
+    BTHH_ERR_AUTH_FAILED,         /* authentication fail */
+    BTHH_ERR_HDL
+}bthh_status_t;
+
+/* Protocol modes */
+typedef enum {
+    BTHH_REPORT_MODE       = 0x00,
+    BTHH_BOOT_MODE         = 0x01,
+    BTHH_UNSUPPORTED_MODE  = 0xff
+}bthh_protocol_mode_t;
+
+/* Report types */
+typedef enum {
+    BTHH_INPUT_REPORT      = 1,
+    BTHH_OUTPUT_REPORT,
+    BTHH_FEATURE_REPORT
+}bthh_report_type_t;
+
+typedef struct
+{
+    int         attr_mask;
+    uint8_t     sub_class;
+    uint8_t     app_id;
+    int         vendor_id;
+    int         product_id;
+    int         version;
+    uint8_t     ctry_code;
+    int         dl_len;
+    uint8_t     dsc_list[BTHH_MAX_DSC_LEN];
+} bthh_hid_info_t;
+
+/** Callback for connection state change.
+ *  state will have one of the values from bthh_connection_state_t
+ */
+typedef void (* bthh_connection_state_callback)(bt_bdaddr_t *bd_addr, bthh_connection_state_t state);
+
+/** Callback for vitual unplug api.
+ *  the status of the vitual unplug
+ */
+typedef void (* bthh_virtual_unplug_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status);
+
+/** Callback for get hid info
+ *  hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id, version, ctry_code, len
+ */
+typedef void (* bthh_hid_info_callback)(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info);
+
+/** Callback for get/set protocal api.
+ *  the protocol mode is one of the value from bthh_protocol_mode_t
+ */
+typedef void (* bthh_protocol_mode_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode);
+
+/** Callback for get/set_idle_time api.
+ */
+typedef void (* bthh_idle_time_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, int idle_rate);
+
+
+/** Callback for get report api.
+ *  if staus is ok rpt_data contains the report data
+ */
+typedef void (* bthh_get_report_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, uint8_t* rpt_data, int rpt_size);
+
+
+/** BT-HH callback structure. */
+typedef struct {
+    /** set to sizeof(BtHfCallbacks) */
+    size_t      size;
+    bthh_connection_state_callback  connection_state_cb;
+    bthh_hid_info_callback          hid_info_cb;
+    bthh_protocol_mode_callback     protocol_mode_cb;
+    bthh_idle_time_callback         idle_time_cb;
+    bthh_get_report_callback        get_report_cb;
+    bthh_virtual_unplug_callback    virtual_unplug_cb;
+
+} bthh_callbacks_t;
+
+
+
+/** Represents the standard BT-HH interface. */
+typedef struct {
+
+    /** set to sizeof(BtHhInterface) */
+    size_t          size;
+
+    /**
+     * Register the BtHh callbacks
+     */
+    bt_status_t (*init)( bthh_callbacks_t* callbacks );
+
+    /** connect to hid device */
+    bt_status_t (*connect)( bt_bdaddr_t *bd_addr);
+
+    /** dis-connect from hid device */
+    bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );
+
+    /** Virtual UnPlug (VUP) the specified HID device */
+    bt_status_t (*virtual_unplug)(bt_bdaddr_t *bd_addr);
+
+    /** Set the HID device descriptor for the specified HID device. */
+    bt_status_t (*set_info)(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info );
+
+    /** Get the HID proto mode. */
+    bt_status_t (*get_protocol) (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode);
+
+    /** Set the HID proto mode. */
+    bt_status_t (*set_protocol)(bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode);
+
+    /** Send a GET_REPORT to HID device. */
+    bt_status_t (*get_report)(bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, uint8_t reportId, int bufferSize);
+
+    /** Send a SET_REPORT to HID device. */
+    bt_status_t (*set_report)(bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, char* report);
+
+    /** Send data to HID device. */
+    bt_status_t (*send_data)(bt_bdaddr_t *bd_addr, char* data);
+
+       /** Closes the interface. */
+    void  (*cleanup)( void );
+
+} bthh_interface_t;
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HH_H */
+
+
diff --git a/android/hardware/bt_hl.h b/android/hardware/bt_hl.h
new file mode 100644 (file)
index 0000000..bd29e3a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HL_H
+#define ANDROID_INCLUDE_BT_HL_H
+
+__BEGIN_DECLS
+
+/* HL connection states */
+
+typedef enum
+{
+    BTHL_MDEP_ROLE_SOURCE,
+    BTHL_MDEP_ROLE_SINK
+} bthl_mdep_role_t;
+
+typedef enum {
+    BTHL_APP_REG_STATE_REG_SUCCESS,
+    BTHL_APP_REG_STATE_REG_FAILED,
+    BTHL_APP_REG_STATE_DEREG_SUCCESS,
+    BTHL_APP_REG_STATE_DEREG_FAILED
+} bthl_app_reg_state_t;
+
+typedef enum
+{
+    BTHL_CHANNEL_TYPE_RELIABLE,
+    BTHL_CHANNEL_TYPE_STREAMING,
+    BTHL_CHANNEL_TYPE_ANY
+} bthl_channel_type_t;
+
+
+/* HL connection states */
+typedef enum {
+    BTHL_CONN_STATE_CONNECTING,
+    BTHL_CONN_STATE_CONNECTED,
+    BTHL_CONN_STATE_DISCONNECTING,
+    BTHL_CONN_STATE_DISCONNECTED,
+    BTHL_CONN_STATE_DESTROYED
+} bthl_channel_state_t;
+
+typedef struct
+{
+    bthl_mdep_role_t        mdep_role;
+    int                     data_type;
+    bthl_channel_type_t     channel_type;
+    const char                   *mdep_description; /* MDEP description to be used in the SDP (optional); null terminated */
+} bthl_mdep_cfg_t;
+
+typedef struct
+{
+    const char      *application_name;
+    const char      *provider_name;   /* provider name to be used in the SDP (optional); null terminated */
+    const char      *srv_name;        /* service name to be used in the SDP (optional); null terminated*/
+    const char      *srv_desp;        /* service description to be used in the SDP (optional); null terminated */
+    int             number_of_mdeps;
+    bthl_mdep_cfg_t *mdep_cfg;  /* Dynamic array */
+} bthl_reg_param_t;
+
+/** Callback for application registration status.
+ *  state will have one of the values from  bthl_app_reg_state_t
+ */
+typedef void (* bthl_app_reg_state_callback)(int app_id, bthl_app_reg_state_t state);
+
+/** Callback for channel connection state change.
+ *  state will have one of the values from
+ *  bthl_connection_state_t and fd (file descriptor)
+ */
+typedef void (* bthl_channel_state_callback)(int app_id, bt_bdaddr_t *bd_addr, int mdep_cfg_index, int channel_id, bthl_channel_state_t state, int fd);
+
+/** BT-HL callback structure. */
+typedef struct {
+    /** set to sizeof(bthl_callbacks_t) */
+    size_t      size;
+    bthl_app_reg_state_callback     app_reg_state_cb;
+    bthl_channel_state_callback     channel_state_cb;
+} bthl_callbacks_t;
+
+
+/** Represents the standard BT-HL interface. */
+typedef struct {
+
+    /** set to sizeof(bthl_interface_t)  */
+    size_t          size;
+
+    /**
+     * Register the Bthl callbacks
+     */
+    bt_status_t (*init)( bthl_callbacks_t* callbacks );
+
+    /** Register HL application */
+    bt_status_t (*register_application) ( bthl_reg_param_t *p_reg_param, int *app_id);
+
+    /** Unregister HL application */
+    bt_status_t (*unregister_application) (int app_id);
+
+    /** connect channel */
+    bt_status_t (*connect_channel)(int app_id, bt_bdaddr_t *bd_addr, int mdep_cfg_index, int *channel_id);
+
+    /** destroy channel */
+    bt_status_t (*destroy_channel)(int channel_id);
+
+    /** Close the  Bthl callback **/
+    void (*cleanup)(void);
+
+} bthl_interface_t;
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HL_H */
+
+
diff --git a/android/hardware/bt_pan.h b/android/hardware/bt_pan.h
new file mode 100644 (file)
index 0000000..c8b36b4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_PAN_H
+#define ANDROID_INCLUDE_BT_PAN_H
+
+__BEGIN_DECLS
+
+#define BTPAN_ROLE_NONE      0
+#define BTPAN_ROLE_PANNAP    1
+#define BTPAN_ROLE_PANU      2
+
+typedef enum {
+    BTPAN_STATE_CONNECTED       = 0,
+    BTPAN_STATE_CONNECTING      = 1,
+    BTPAN_STATE_DISCONNECTED    = 2,
+    BTPAN_STATE_DISCONNECTING   = 3
+} btpan_connection_state_t;
+
+typedef enum {
+    BTPAN_STATE_ENABLED = 0,
+    BTPAN_STATE_DISABLED = 1
+} btpan_control_state_t;
+
+/**
+* Callback for pan connection state
+*/
+typedef void (*btpan_connection_state_callback)(btpan_connection_state_t state, bt_status_t error,
+                                                const bt_bdaddr_t *bd_addr, int local_role, int remote_role);
+typedef void (*btpan_control_state_callback)(btpan_control_state_t state, bt_status_t error,
+                                            int local_role, const char* ifname);
+
+typedef struct {
+    size_t size;
+    btpan_control_state_callback control_state_cb;
+    btpan_connection_state_callback connection_state_cb;
+} btpan_callbacks_t;
+typedef struct {
+    /** set to size of this struct*/
+    size_t          size;
+    /**
+     * Initialize the pan interface and register the btpan callbacks
+     */
+    bt_status_t (*init)(const btpan_callbacks_t* callbacks);
+    /*
+     * enable the pan service by specified role. The result state of
+     * enabl will be returned by btpan_control_state_callback. when pan-nap is enabled,
+     * the state of connecting panu device will be notified by btpan_connection_state_callback
+     */
+    bt_status_t (*enable)(int local_role);
+    /*
+     * get current pan local role
+     */
+    int (*get_local_role)(void);
+    /**
+     * start bluetooth pan connection to the remote device by specified pan role. The result state will be
+     * returned by btpan_connection_state_callback
+     */
+    bt_status_t (*connect)(const bt_bdaddr_t *bd_addr, int local_role, int remote_role);
+    /**
+     * stop bluetooth pan connection. The result state will be returned by btpan_connection_state_callback
+     */
+    bt_status_t (*disconnect)(const bt_bdaddr_t *bd_addr);
+
+    /**
+     * Cleanup the pan interface
+     */
+    void (*cleanup)(void);
+
+} btpan_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_PAN_H */
diff --git a/android/hardware/bt_rc.h b/android/hardware/bt_rc.h
new file mode 100644 (file)
index 0000000..d455543
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_RC_H
+#define ANDROID_INCLUDE_BT_RC_H
+
+__BEGIN_DECLS
+
+/* Macros */
+#define BTRC_MAX_ATTR_STR_LEN       255
+#define BTRC_UID_SIZE               8
+#define BTRC_MAX_APP_SETTINGS       8
+#define BTRC_MAX_FOLDER_DEPTH       4
+#define BTRC_MAX_APP_ATTR_SIZE      16
+#define BTRC_MAX_ELEM_ATTR_SIZE     7
+
+typedef uint8_t btrc_uid_t[BTRC_UID_SIZE];
+
+typedef enum {
+    BTRC_FEAT_NONE = 0x00,    /* AVRCP 1.0 */
+    BTRC_FEAT_METADATA = 0x01,    /* AVRCP 1.3 */
+    BTRC_FEAT_ABSOLUTE_VOLUME = 0x02,    /* Supports TG role and volume sync */
+    BTRC_FEAT_BROWSE = 0x04,    /* AVRCP 1.4 and up, with Browsing support */
+} btrc_remote_features_t;
+
+typedef enum {
+    BTRC_PLAYSTATE_STOPPED = 0x00,    /* Stopped */
+    BTRC_PLAYSTATE_PLAYING = 0x01,    /* Playing */
+    BTRC_PLAYSTATE_PAUSED = 0x02,    /* Paused  */
+    BTRC_PLAYSTATE_FWD_SEEK = 0x03,    /* Fwd Seek*/
+    BTRC_PLAYSTATE_REV_SEEK = 0x04,    /* Rev Seek*/
+    BTRC_PLAYSTATE_ERROR = 0xFF,    /* Error   */
+} btrc_play_status_t;
+
+typedef enum {
+    BTRC_EVT_PLAY_STATUS_CHANGED = 0x01,
+    BTRC_EVT_TRACK_CHANGE = 0x02,
+    BTRC_EVT_TRACK_REACHED_END = 0x03,
+    BTRC_EVT_TRACK_REACHED_START = 0x04,
+    BTRC_EVT_PLAY_POS_CHANGED = 0x05,
+    BTRC_EVT_APP_SETTINGS_CHANGED = 0x08,
+} btrc_event_id_t;
+
+typedef enum {
+    BTRC_NOTIFICATION_TYPE_INTERIM = 0,
+    BTRC_NOTIFICATION_TYPE_CHANGED = 1,
+} btrc_notification_type_t;
+
+typedef enum {
+    BTRC_PLAYER_ATTR_EQUALIZER = 0x01,
+    BTRC_PLAYER_ATTR_REPEAT = 0x02,
+    BTRC_PLAYER_ATTR_SHUFFLE = 0x03,
+    BTRC_PLAYER_ATTR_SCAN = 0x04,
+} btrc_player_attr_t;
+
+typedef enum {
+    BTRC_MEDIA_ATTR_TITLE = 0x01,
+    BTRC_MEDIA_ATTR_ARTIST = 0x02,
+    BTRC_MEDIA_ATTR_ALBUM = 0x03,
+    BTRC_MEDIA_ATTR_TRACK_NUM = 0x04,
+    BTRC_MEDIA_ATTR_NUM_TRACKS = 0x05,
+    BTRC_MEDIA_ATTR_GENRE = 0x06,
+    BTRC_MEDIA_ATTR_PLAYING_TIME = 0x07,
+} btrc_media_attr_t;
+
+typedef enum {
+    BTRC_PLAYER_VAL_OFF_REPEAT = 0x01,
+    BTRC_PLAYER_VAL_SINGLE_REPEAT = 0x02,
+    BTRC_PLAYER_VAL_ALL_REPEAT = 0x03,
+    BTRC_PLAYER_VAL_GROUP_REPEAT = 0x04
+} btrc_player_repeat_val_t;
+
+typedef enum {
+    BTRC_PLAYER_VAL_OFF_SHUFFLE = 0x01,
+    BTRC_PLAYER_VAL_ALL_SHUFFLE = 0x02,
+    BTRC_PLAYER_VAL_GROUP_SHUFFLE = 0x03
+} btrc_player_shuffle_val_t;
+
+typedef enum {
+    BTRC_STS_BAD_CMD        = 0x00, /* Invalid command */
+    BTRC_STS_BAD_PARAM      = 0x01, /* Invalid parameter */
+    BTRC_STS_NOT_FOUND      = 0x02, /* Specified parameter is wrong or not found */
+    BTRC_STS_INTERNAL_ERR   = 0x03, /* Internal Error */
+    BTRC_STS_NO_ERROR       = 0x04  /* Operation Success */
+} btrc_status_t;
+
+typedef struct {
+    uint8_t num_attr;
+    uint8_t attr_ids[BTRC_MAX_APP_SETTINGS];
+    uint8_t attr_values[BTRC_MAX_APP_SETTINGS];
+} btrc_player_settings_t;
+
+typedef union
+{
+    btrc_play_status_t play_status;
+    btrc_uid_t track; /* queue position in NowPlaying */
+    uint32_t song_pos;
+    btrc_player_settings_t player_setting;
+} btrc_register_notification_t;
+
+typedef struct {
+    uint8_t id; /* can be attr_id or value_id */
+    uint8_t text[BTRC_MAX_ATTR_STR_LEN];
+} btrc_player_setting_text_t;
+
+typedef struct {
+    uint32_t attr_id;
+    uint8_t text[BTRC_MAX_ATTR_STR_LEN];
+} btrc_element_attr_val_t;
+
+/** Callback for the controller's supported feautres */
+typedef void (* btrc_remote_features_callback)(bt_bdaddr_t *bd_addr,
+                                                      btrc_remote_features_t features);
+
+/** Callback for play status request */
+typedef void (* btrc_get_play_status_callback)();
+
+/** Callback for list player application attributes (Shuffle, Repeat,...) */
+typedef void (* btrc_list_player_app_attr_callback)();
+
+/** Callback for list player application attributes (Shuffle, Repeat,...) */
+typedef void (* btrc_list_player_app_values_callback)(btrc_player_attr_t attr_id);
+
+/** Callback for getting the current player application settings value
+**  num_attr: specifies the number of attribute ids contained in p_attrs
+*/
+typedef void (* btrc_get_player_app_value_callback) (uint8_t num_attr, btrc_player_attr_t *p_attrs);
+
+/** Callback for getting the player application settings attributes' text
+**  num_attr: specifies the number of attribute ids contained in p_attrs
+*/
+typedef void (* btrc_get_player_app_attrs_text_callback) (uint8_t num_attr, btrc_player_attr_t *p_attrs);
+
+/** Callback for getting the player application settings values' text
+**  num_attr: specifies the number of value ids contained in p_vals
+*/
+typedef void (* btrc_get_player_app_values_text_callback) (uint8_t attr_id, uint8_t num_val, uint8_t *p_vals);
+
+/** Callback for setting the player application settings values */
+typedef void (* btrc_set_player_app_value_callback) (btrc_player_settings_t *p_vals);
+
+/** Callback to fetch the get element attributes of the current song
+**  num_attr: specifies the number of attributes requested in p_attrs
+*/
+typedef void (* btrc_get_element_attr_callback) (uint8_t num_attr, btrc_media_attr_t *p_attrs);
+
+/** Callback for register notification (Play state change/track change/...)
+**  param: Is only valid if event_id is BTRC_EVT_PLAY_POS_CHANGED
+*/
+typedef void (* btrc_register_notification_callback) (btrc_event_id_t event_id, uint32_t param);
+
+/* AVRCP 1.4 Enhancements */
+/** Callback for volume change on CT
+**  volume: Current volume setting on the CT (0-127)
+*/
+typedef void (* btrc_volume_change_callback) (uint8_t volume, uint8_t ctype);
+
+/** Callback for passthrough commands */
+typedef void (* btrc_passthrough_cmd_callback) (int id, int key_state);
+
+/** BT-RC callback structure. */
+typedef struct {
+    /** set to sizeof(BtRcCallbacks) */
+    size_t      size;
+    btrc_remote_features_callback               remote_features_cb;
+    btrc_get_play_status_callback               get_play_status_cb;
+    btrc_list_player_app_attr_callback          list_player_app_attr_cb;
+    btrc_list_player_app_values_callback        list_player_app_values_cb;
+    btrc_get_player_app_value_callback          get_player_app_value_cb;
+    btrc_get_player_app_attrs_text_callback     get_player_app_attrs_text_cb;
+    btrc_get_player_app_values_text_callback    get_player_app_values_text_cb;
+    btrc_set_player_app_value_callback          set_player_app_value_cb;
+    btrc_get_element_attr_callback              get_element_attr_cb;
+    btrc_register_notification_callback         register_notification_cb;
+    btrc_volume_change_callback                 volume_change_cb;
+    btrc_passthrough_cmd_callback               passthrough_cmd_cb;
+} btrc_callbacks_t;
+
+/** Represents the standard BT-RC interface. */
+typedef struct {
+
+    /** set to sizeof(BtRcInterface) */
+    size_t          size;
+    /**
+     * Register the BtRc callbacks
+     */
+    bt_status_t (*init)( btrc_callbacks_t* callbacks );
+
+    /** Respose to GetPlayStatus request. Contains the current
+    **  1. Play status
+    **  2. Song duration/length
+    **  3. Song position
+    */
+    bt_status_t (*get_play_status_rsp)( btrc_play_status_t play_status, uint32_t song_len, uint32_t song_pos);
+
+    /** Lists the support player application attributes (Shuffle/Repeat/...)
+    **  num_attr: Specifies the number of attributes contained in the pointer p_attrs
+    */
+    bt_status_t (*list_player_app_attr_rsp)( int num_attr, btrc_player_attr_t *p_attrs);
+
+    /** Lists the support player application attributes (Shuffle Off/On/Group)
+    **  num_val: Specifies the number of values contained in the pointer p_vals
+    */
+    bt_status_t (*list_player_app_value_rsp)( int num_val, uint8_t *p_vals);
+
+    /** Returns the current application attribute values for each of the specified attr_id */
+    bt_status_t (*get_player_app_value_rsp)( btrc_player_settings_t *p_vals);
+
+    /** Returns the application attributes text ("Shuffle"/"Repeat"/...)
+    **  num_attr: Specifies the number of attributes' text contained in the pointer p_attrs
+    */
+    bt_status_t (*get_player_app_attr_text_rsp)( int num_attr, btrc_player_setting_text_t *p_attrs);
+
+    /** Returns the application attributes text ("Shuffle"/"Repeat"/...)
+    **  num_attr: Specifies the number of attribute values' text contained in the pointer p_vals
+    */
+    bt_status_t (*get_player_app_value_text_rsp)( int num_val, btrc_player_setting_text_t *p_vals);
+
+    /** Returns the current songs' element attributes text ("Title"/"Album"/"Artist")
+    **  num_attr: Specifies the number of attributes' text contained in the pointer p_attrs
+    */
+    bt_status_t (*get_element_attr_rsp)( uint8_t num_attr, btrc_element_attr_val_t *p_attrs);
+
+    /** Response to set player attribute request ("Shuffle"/"Repeat")
+    **  rsp_status: Status of setting the player attributes for the current media player
+    */
+    bt_status_t (*set_player_app_value_rsp)(btrc_status_t rsp_status);
+
+    /* Response to the register notification request (Play state change/track change/...).
+    ** event_id: Refers to the event_id this notification change corresponds too
+    ** type: Response type - interim/changed
+    ** p_params: Based on the event_id, this parameter should be populated
+    */
+    bt_status_t (*register_notification_rsp)(btrc_event_id_t event_id,
+                                             btrc_notification_type_t type,
+                                             btrc_register_notification_t *p_param);
+
+    /* AVRCP 1.4 enhancements */
+
+    /**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 opposed to absolute volume level
+    ** volume: Should be in the range 0-127. bit7 is reseved and cannot be set
+    */
+    bt_status_t (*set_volume)(uint8_t volume);
+
+    /** Closes the interface. */
+    void  (*cleanup)( void );
+} btrc_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_RC_H */
diff --git a/android/hardware/bt_sock.h b/android/hardware/bt_sock.h
new file mode 100644 (file)
index 0000000..a4aa046
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_SOCK_H
+#define ANDROID_INCLUDE_BT_SOCK_H
+
+__BEGIN_DECLS
+
+#define BTSOCK_FLAG_ENCRYPT 1
+#define BTSOCK_FLAG_AUTH (1 << 1)
+
+typedef enum {
+    BTSOCK_RFCOMM = 1,
+    BTSOCK_SCO = 2,
+    BTSOCK_L2CAP = 3
+} btsock_type_t;
+
+/** Represents the standard BT SOCKET interface. */
+typedef struct {
+    short size;
+    bt_bdaddr_t bd_addr;
+    int channel;
+    int status;
+} __attribute__((packed)) sock_connect_signal_t;
+
+typedef struct {
+
+    /** set to size of this struct*/
+    size_t          size;
+    /**
+     * listen to a rfcomm uuid or channel. It returns the socket fd from which
+     * btsock_connect_signal can be read out when a remote device connected
+     */
+    bt_status_t (*listen)(btsock_type_t type, const char* service_name, const uint8_t* service_uuid, int channel, int* sock_fd, int flags);
+    /*
+     * connect to a rfcomm uuid channel of remote device, It returns the socket fd from which
+     * the btsock_connect_signal and a new socket fd to be accepted can be read out when connected
+     */
+    bt_status_t (*connect)(const bt_bdaddr_t *bd_addr, btsock_type_t type, const uint8_t* uuid, int channel, int* sock_fd, int flags);
+
+} btsock_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_SOCK_H */
diff --git a/android/hardware/hardware.h b/android/hardware/hardware.h
new file mode 100644 (file)
index 0000000..c7e8cc7
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2008 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 ANDROID_INCLUDE_HARDWARE_HARDWARE_H
+#define ANDROID_INCLUDE_HARDWARE_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * Value for the hw_module_t.tag field
+ */
+
+#define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
+
+#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
+#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
+
+#define HARDWARE_MAKE_API_VERSION(maj,min) \
+            ((((maj) & 0xff) << 8) | ((min) & 0xff))
+
+#define HARDWARE_MAKE_API_VERSION_2(maj,min,hdr) \
+            ((((maj) & 0xff) << 24) | (((min) & 0xff) << 16) | ((hdr) & 0xffff))
+#define HARDWARE_API_VERSION_2_MAJ_MIN_MASK 0xffff0000
+#define HARDWARE_API_VERSION_2_HEADER_MASK  0x0000ffff
+
+
+/*
+ * The current HAL API version.
+ *
+ * All module implementations must set the hw_module_t.hal_api_version field
+ * to this value when declaring the module with HAL_MODULE_INFO_SYM.
+ *
+ * Note that previous implementations have always set this field to 0.
+ * Therefore, libhardware HAL API will always consider versions 0.0 and 1.0
+ * to be 100% binary compatible.
+ *
+ */
+#define HARDWARE_HAL_API_VERSION HARDWARE_MAKE_API_VERSION(1, 0)
+
+/*
+ * Helper macros for module implementors.
+ *
+ * The derived modules should provide convenience macros for supported
+ * versions so that implementations can explicitly specify module/device
+ * versions at definition time.
+ *
+ * Use this macro to set the hw_module_t.module_api_version field.
+ */
+#define HARDWARE_MODULE_API_VERSION(maj,min) HARDWARE_MAKE_API_VERSION(maj,min)
+#define HARDWARE_MODULE_API_VERSION_2(maj,min,hdr) HARDWARE_MAKE_API_VERSION_2(maj,min,hdr)
+
+/*
+ * Use this macro to set the hw_device_t.version field
+ */
+#define HARDWARE_DEVICE_API_VERSION(maj,min) HARDWARE_MAKE_API_VERSION(maj,min)
+#define HARDWARE_DEVICE_API_VERSION_2(maj,min,hdr) HARDWARE_MAKE_API_VERSION_2(maj,min,hdr)
+
+struct hw_module_t;
+struct hw_module_methods_t;
+struct hw_device_t;
+
+/**
+ * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
+ * and the fields of this data structure must begin with hw_module_t
+ * followed by module specific information.
+ */
+typedef struct hw_module_t {
+    /** tag must be initialized to HARDWARE_MODULE_TAG */
+    uint32_t tag;
+
+    /**
+     * The API version of the implemented module. The module owner is
+     * responsible for updating the version when a module interface has
+     * changed.
+     *
+     * The derived modules such as gralloc and audio own and manage this field.
+     * The module user must interpret the version field to decide whether or
+     * not to inter-operate with the supplied module implementation.
+     * For example, SurfaceFlinger is responsible for making sure that
+     * it knows how to manage different versions of the gralloc-module API,
+     * and AudioFlinger must know how to do the same for audio-module API.
+     *
+     * The module API version should include a major and a minor component.
+     * For example, version 1.0 could be represented as 0x0100. This format
+     * implies that versions 0x0100-0x01ff are all API-compatible.
+     *
+     * In the future, libhardware will expose a hw_get_module_version()
+     * (or equivalent) function that will take minimum/maximum supported
+     * versions as arguments and would be able to reject modules with
+     * versions outside of the supplied range.
+     */
+    uint16_t module_api_version;
+#define version_major module_api_version
+    /**
+     * version_major/version_minor defines are supplied here for temporary
+     * source code compatibility. They will be removed in the next version.
+     * ALL clients must convert to the new version format.
+     */
+
+    /**
+     * The API version of the HAL module interface. This is meant to
+     * version the hw_module_t, hw_module_methods_t, and hw_device_t
+     * structures and definitions.
+     *
+     * The HAL interface owns this field. Module users/implementations
+     * must NOT rely on this value for version information.
+     *
+     * Presently, 0 is the only valid value.
+     */
+    uint16_t hal_api_version;
+#define version_minor hal_api_version
+
+    /** Identifier of module */
+    const char *id;
+
+    /** Name of this module */
+    const char *name;
+
+    /** Author/owner/implementor of the module */
+    const char *author;
+
+    /** Modules methods */
+    struct hw_module_methods_t* methods;
+
+    /** module's dso */
+    void* dso;
+
+    /** padding to 128 bytes, reserved for future use */
+    uint32_t reserved[32-7];
+
+} hw_module_t;
+
+typedef struct hw_module_methods_t {
+    /** Open a specific device */
+    int (*open)(const struct hw_module_t* module, const char* id,
+            struct hw_device_t** device);
+
+} hw_module_methods_t;
+
+/**
+ * Every device data structure must begin with hw_device_t
+ * followed by module specific public methods and attributes.
+ */
+typedef struct hw_device_t {
+    /** tag must be initialized to HARDWARE_DEVICE_TAG */
+    uint32_t tag;
+
+    /**
+     * Version of the module-specific device API. This value is used by
+     * the derived-module user to manage different device implementations.
+     *
+     * The module user is responsible for checking the module_api_version
+     * and device version fields to ensure that the user is capable of
+     * communicating with the specific module implementation.
+     *
+     * One module can support multiple devices with different versions. This
+     * can be useful when a device interface changes in an incompatible way
+     * but it is still necessary to support older implementations at the same
+     * time. One such example is the Camera 2.0 API.
+     *
+     * This field is interpreted by the module user and is ignored by the
+     * HAL interface itself.
+     */
+    uint32_t version;
+
+    /** reference to the module this device belongs to */
+    struct hw_module_t* module;
+
+    /** padding reserved for future use */
+    uint32_t reserved[12];
+
+    /** Close this device */
+    int (*close)(struct hw_device_t* device);
+
+} hw_device_t;
+
+/**
+ * Name of the hal_module_info
+ */
+#define HAL_MODULE_INFO_SYM         HMI
+
+/**
+ * Name of the hal_module_info as a string
+ */
+#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
+
+/**
+ * Get the module info associated with a module by id.
+ *
+ * @return: 0 == success, <0 == error and *module == NULL
+ */
+int hw_get_module(const char *id, const struct hw_module_t **module);
+
+/**
+ * Get the module info associated with a module instance by class 'class_id'
+ * and instance 'inst'.
+ *
+ * Some modules types necessitate multiple instances. For example audio supports
+ * multiple concurrent interfaces and thus 'audio' is the module class
+ * and 'primary' or 'a2dp' are module interfaces. This implies that the files
+ * providing these modules would be named audio.primary.<variant>.so and
+ * audio.a2dp.<variant>.so
+ *
+ * @return: 0 == success, <0 == error and *module == NULL
+ */
+int hw_get_module_by_class(const char *class_id, const char *inst,
+                           const struct hw_module_t **module);
+
+__END_DECLS
+
+#endif  /* ANDROID_INCLUDE_HARDWARE_HARDWARE_H */
diff --git a/android/hidhost.c b/android/hidhost.c
new file mode 100644 (file)
index 0000000..f5a607c
--- /dev/null
@@ -0,0 +1,1240 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include "btio/btio.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+#include "src/shared/mgmt.h"
+#include "src/sdp-client.h"
+#include "src/glib-helper.h"
+#include "profiles/input/uhid_copy.h"
+
+#include "log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "hidhost.h"
+#include "utils.h"
+
+#define L2CAP_PSM_HIDP_CTRL    0x11
+#define L2CAP_PSM_HIDP_INTR    0x13
+#define UHID_DEVICE_FILE       "/dev/uhid"
+
+/* HID message types */
+#define HID_MSG_CONTROL                0x10
+#define HID_MSG_GET_REPORT     0x40
+#define HID_MSG_SET_REPORT     0x50
+#define HID_MSG_GET_PROTOCOL   0x60
+#define HID_MSG_SET_PROTOCOL   0x70
+#define HID_MSG_DATA           0xa0
+
+/* HID data types */
+#define HID_DATA_TYPE_INPUT    0x01
+#define HID_DATA_TYPE_OUTPUT   0x02
+#define HID_DATA_TYPE_FEATURE  0x03
+
+/* HID protocol header parameters */
+#define HID_PROTO_BOOT         0x00
+#define HID_PROTO_REPORT       0x01
+
+/* HID GET REPORT Size Field */
+#define HID_GET_REPORT_SIZE_FIELD      0x08
+
+/* HID Virtual Cable Unplug */
+#define HID_VIRTUAL_CABLE_UNPLUG       0x05
+
+static bdaddr_t adapter_addr;
+
+static int notification_sk = -1;
+static GIOChannel *ctrl_io = NULL;
+static GIOChannel *intr_io = NULL;
+static GSList *devices = NULL;
+
+struct hid_device {
+       bdaddr_t        dst;
+       uint8_t         state;
+       uint8_t         subclass;
+       uint16_t        vendor;
+       uint16_t        product;
+       uint16_t        version;
+       uint8_t         country;
+       int             rd_size;
+       void            *rd_data;
+       uint8_t         boot_dev;
+       GIOChannel      *ctrl_io;
+       GIOChannel      *intr_io;
+       guint           ctrl_watch;
+       guint           intr_watch;
+       int             uhid_fd;
+       guint           uhid_watch_id;
+       uint8_t         last_hid_msg;
+};
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+       const struct hid_device *dev = s;
+       const bdaddr_t *dst = user_data;
+
+       return bacmp(&dev->dst, dst);
+}
+
+static void uhid_destroy(int fd)
+{
+       struct uhid_event ev;
+
+       /* destroy uHID device */
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_DESTROY;
+
+       if (write(fd, &ev, sizeof(ev)) < 0)
+               error("Failed to destroy uHID device: %s (%d)",
+                                               strerror(errno), errno);
+
+       close(fd);
+}
+
+static void hid_device_free(struct hid_device *dev)
+{
+       if (dev->ctrl_watch > 0)
+               g_source_remove(dev->ctrl_watch);
+
+       if (dev->intr_watch > 0)
+               g_source_remove(dev->intr_watch);
+
+       if (dev->intr_io)
+               g_io_channel_unref(dev->intr_io);
+
+       if (dev->ctrl_io)
+               g_io_channel_unref(dev->ctrl_io);
+
+       if (dev->uhid_watch_id) {
+               g_source_remove(dev->uhid_watch_id);
+               dev->uhid_watch_id = 0;
+       }
+
+       if (dev->uhid_fd > 0)
+               uhid_destroy(dev->uhid_fd);
+
+       g_free(dev->rd_data);
+
+       devices = g_slist_remove(devices, dev);
+       g_free(dev);
+}
+
+static void handle_uhid_event(struct hid_device *dev, struct uhid_event *ev)
+{
+       int fd, i;
+       uint8_t *req = NULL;
+       uint8_t req_size = 0;
+
+       if (!(dev->ctrl_io))
+               return;
+
+       req_size = 1 + (ev->u.output.size / 2);
+       req = g_try_malloc0(req_size);
+       if (!req)
+               return;
+
+       req[0] = HID_MSG_SET_REPORT | ev->u.output.rtype;
+       for (i = 0; i < (req_size - 1); i++)
+               sscanf((char *) &(ev->u.output.data)[i * 2],
+                                                       "%hhx", &req[1 + i]);
+
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, req, req_size) < 0)
+               error("error writing set_report: %s (%d)",
+                                               strerror(errno), errno);
+
+       g_free(req);
+}
+
+static gboolean uhid_event_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct hid_device *dev = user_data;
+       struct uhid_event ev;
+       ssize_t bread;
+       int fd;
+
+       DBG("");
+
+       if (cond & (G_IO_ERR | G_IO_NVAL))
+               goto failed;
+
+       fd = g_io_channel_unix_get_fd(io);
+       memset(&ev, 0, sizeof(ev));
+
+       bread = read(fd, &ev, sizeof(ev));
+       if (bread < 0) {
+               DBG("read: %s (%d)", strerror(errno), errno);
+               goto failed;
+       }
+
+       DBG("uHID event type %d received", ev.type);
+
+       switch (ev.type) {
+       case UHID_START:
+       case UHID_STOP:
+               /* These are called to start and stop the underlying hardware.
+                * We open the channels before creating the device so the
+                * hardware is always ready. No need to handle these.
+                * The kernel never destroys a device itself! Only an explicit
+                * UHID_DESTROY request can remove a device. */
+
+               break;
+       case UHID_OPEN:
+       case UHID_CLOSE:
+               /* OPEN/CLOSE are sent whenever user-space opens any interface
+                * provided by the kernel HID device. Whenever the open-count
+                * is non-zero we must be ready for I/O. As long as it is zero,
+                * we can decide to drop all I/O and put the device
+                * asleep This is optional, though. */
+               break;
+       case UHID_OUTPUT:
+       case UHID_FEATURE:
+               handle_uhid_event(dev, &ev);
+               break;
+       case UHID_OUTPUT_EV:
+               /* This is only sent by kernels prior to linux-3.11. It
+                * requires us to parse HID-descriptors in user-space to
+                * properly handle it. This is redundant as the kernel
+                * does it already. That's why newer kernels assemble
+                * the output-reports and send it to us via UHID_OUTPUT. */
+               DBG("UHID_OUTPUT_EV unsupported");
+               break;
+       default:
+               warn("unexpected uHID event");
+       }
+
+       return TRUE;
+
+failed:
+       dev->uhid_watch_id = 0;
+       return FALSE;
+}
+
+static gboolean intr_io_watch_cb(GIOChannel *chan, gpointer data)
+{
+       struct hid_device *dev = data;
+       uint8_t buf[UHID_DATA_MAX];
+       struct uhid_event ev;
+       int fd, bread;
+
+       /* Wait uHID if not ready */
+       if (dev->uhid_fd < 0)
+               return TRUE;
+
+       fd = g_io_channel_unix_get_fd(chan);
+       bread = read(fd, buf, sizeof(buf));
+       if (bread < 0) {
+               error("read: %s(%d)", strerror(errno), -errno);
+               return TRUE;
+       }
+
+       /* Discard non-data packets */
+       if (bread == 0 || buf[0] != (HID_MSG_DATA | HID_DATA_TYPE_INPUT))
+               return TRUE;
+
+       /* send data to uHID device skipping HIDP header byte */
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_INPUT;
+       ev.u.input.size = bread - 1;
+       memcpy(ev.u.input.data, &buf[1], ev.u.input.size);
+
+       if (write(dev->uhid_fd, &ev, sizeof(ev)) < 0)
+               DBG("uhid write: %s (%d)", strerror(errno), errno);
+
+       return TRUE;
+}
+
+static void bt_hid_notify_state(struct hid_device *dev, uint8_t state)
+{
+       struct hal_ev_hidhost_conn_state ev;
+       char address[18];
+
+       if (dev->state == state)
+               return;
+
+       dev->state = state;
+
+       ba2str(&dev->dst, address);
+       DBG("device %s state %u", address, state);
+
+       bdaddr2android(&dev->dst, ev.bdaddr);
+       ev.state = state;
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_HIDHOST,
+                       HAL_EV_HIDHOST_CONN_STATE, sizeof(ev), &ev, -1);
+}
+
+static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond,
+                                                               gpointer data)
+{
+       struct hid_device *dev = data;
+
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+               goto error;
+
+       if (cond & G_IO_IN)
+               return intr_io_watch_cb(chan, data);
+
+error:
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+
+       /* Checking for ctrl_watch avoids a double g_io_channel_shutdown since
+        * it's likely that ctrl_watch_cb has been queued for dispatching in
+        * this mainloop iteration */
+       if ((cond & (G_IO_HUP | G_IO_ERR)) && dev->ctrl_watch)
+               g_io_channel_shutdown(chan, TRUE, NULL);
+
+       /* Close control channel */
+       if (dev->ctrl_io && !(cond & G_IO_NVAL))
+               g_io_channel_shutdown(dev->ctrl_io, TRUE, NULL);
+
+       hid_device_free(dev);
+
+       return FALSE;
+}
+
+static void bt_hid_notify_proto_mode(struct hid_device *dev, uint8_t *buf,
+                                                                       int len)
+{
+       struct hal_ev_hidhost_proto_mode ev;
+       char address[18];
+
+       ba2str(&dev->dst, address);
+       DBG("device %s", address);
+
+       memset(&ev, 0, sizeof(ev));
+       bdaddr2android(&dev->dst, ev.bdaddr);
+
+       if (buf[0] == HID_MSG_DATA) {
+               ev.status = HAL_HIDHOST_STATUS_OK;
+               if (buf[1] == HID_PROTO_REPORT)
+                       ev.mode = HAL_HIDHOST_REPORT_PROTOCOL;
+               else if (buf[1] == HID_PROTO_BOOT)
+                       ev.mode = HAL_HIDHOST_BOOT_PROTOCOL;
+               else
+                       ev.mode = HAL_HIDHOST_UNSUPPORTED_PROTOCOL;
+
+       } else {
+               ev.status = buf[0];
+               ev.mode = HAL_HIDHOST_UNSUPPORTED_PROTOCOL;
+       }
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_HIDHOST,
+                       HAL_EV_HIDHOST_PROTO_MODE, sizeof(ev), &ev, -1);
+}
+
+static void bt_hid_notify_get_report(struct hid_device *dev, uint8_t *buf,
+                                                                       int len)
+{
+       struct hal_ev_hidhost_get_report *ev;
+       int ev_len;
+       char address[18];
+
+       ba2str(&dev->dst, address);
+       DBG("device %s", address);
+
+       ev_len = sizeof(*ev) + sizeof(struct hal_ev_hidhost_get_report) + 1;
+
+       if (!((buf[0] == (HID_MSG_DATA | HID_DATA_TYPE_INPUT)) ||
+                       (buf[0] == (HID_MSG_DATA | HID_DATA_TYPE_OUTPUT)) ||
+                       (buf[0] == (HID_MSG_DATA | HID_DATA_TYPE_FEATURE)))) {
+               ev = g_malloc0(ev_len);
+               ev->status = buf[0];
+               bdaddr2android(&dev->dst, ev->bdaddr);
+               goto send;
+       }
+
+       /* Report porotocol mode reply contains id after hdr, in boot
+        * protocol mode id doesn't exist */
+       ev_len += (dev->boot_dev) ? (len - 1) : (len - 2);
+       ev = g_malloc0(ev_len);
+       ev->status = HAL_HIDHOST_STATUS_OK;
+       bdaddr2android(&dev->dst, ev->bdaddr);
+
+       /* Report porotocol mode reply contains id after hdr, in boot
+        * protocol mode id doesn't exist */
+       if (dev->boot_dev) {
+               ev->len = len - 1;
+               memcpy(ev->data, buf + 1, ev->len);
+       } else {
+               ev->len = len - 2;
+               memcpy(ev->data, buf + 2, ev->len);
+       }
+
+send:
+       ipc_send(notification_sk, HAL_SERVICE_ID_HIDHOST,
+                               HAL_EV_HIDHOST_GET_REPORT, ev_len, ev, -1);
+       g_free(ev);
+}
+
+static void bt_hid_notify_virtual_unplug(struct hid_device *dev,
+                                                       uint8_t *buf, int len)
+{
+       struct hal_ev_hidhost_virtual_unplug ev;
+       char address[18];
+
+       ba2str(&dev->dst, address);
+       DBG("device %s", address);
+       bdaddr2android(&dev->dst, ev.bdaddr);
+
+       ev.status = HAL_HIDHOST_GENERAL_ERROR;
+
+       /* Wait either channels to HUP */
+       if (dev->intr_io && dev->ctrl_io) {
+               g_io_channel_shutdown(dev->intr_io, TRUE, NULL);
+               g_io_channel_shutdown(dev->ctrl_io, TRUE, NULL);
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTING);
+               ev.status = HAL_HIDHOST_STATUS_OK;
+       }
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_HIDHOST,
+                       HAL_EV_HIDHOST_VIRTUAL_UNPLUG, sizeof(ev), &ev, -1);
+
+}
+
+static gboolean ctrl_io_watch_cb(GIOChannel *chan, gpointer data)
+{
+       struct hid_device *dev = data;
+       int fd, bread;
+       uint8_t buf[UHID_DATA_MAX];
+
+       DBG("");
+
+       fd = g_io_channel_unix_get_fd(chan);
+       bread = read(fd, buf, sizeof(buf));
+       if (bread < 0) {
+               error("read: %s(%d)", strerror(errno), -errno);
+               return TRUE;
+       }
+
+       switch (dev->last_hid_msg) {
+       case HID_MSG_GET_PROTOCOL:
+       case HID_MSG_SET_PROTOCOL:
+               bt_hid_notify_proto_mode(dev, buf, bread);
+               break;
+       case HID_MSG_GET_REPORT:
+               bt_hid_notify_get_report(dev, buf, bread);
+               break;
+       }
+
+       if (buf[0] == (HID_MSG_CONTROL | HID_VIRTUAL_CABLE_UNPLUG))
+               bt_hid_notify_virtual_unplug(dev, buf, bread);
+
+       /* reset msg type request */
+       dev->last_hid_msg = 0;
+
+       return TRUE;
+}
+
+static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond,
+                                                               gpointer data)
+{
+       struct hid_device *dev = data;
+
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+               goto error;
+
+       if (cond & G_IO_IN)
+               return ctrl_io_watch_cb(chan, data);
+
+error:
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+
+       /* Checking for intr_watch avoids a double g_io_channel_shutdown since
+        * it's likely that intr_watch_cb has been queued for dispatching in
+        * this mainloop iteration */
+       if ((cond & (G_IO_HUP | G_IO_ERR)) && dev->intr_watch)
+               g_io_channel_shutdown(chan, TRUE, NULL);
+
+       if (dev->intr_io && !(cond & G_IO_NVAL))
+               g_io_channel_shutdown(dev->intr_io, TRUE, NULL);
+
+       hid_device_free(dev);
+
+       return FALSE;
+}
+
+static void bt_hid_set_info(struct hid_device *dev)
+{
+       struct hal_ev_hidhost_info ev;
+
+       DBG("");
+
+       bdaddr2android(&dev->dst, ev.bdaddr);
+       ev.attr = 0; /* TODO: Check what is this field */
+       ev.subclass = dev->subclass;
+       ev.app_id = 0; /* TODO: Check what is this field */
+       ev.vendor = dev->vendor;
+       ev.product = dev->product;
+       ev.version = dev->version;
+       ev.country = dev->country;
+       ev.descr_len = dev->rd_size;
+       memset(ev.descr, 0, sizeof(ev.descr));
+       memcpy(ev.descr, dev->rd_data, ev.descr_len);
+
+       ipc_send(notification_sk, HAL_SERVICE_ID_HIDHOST, HAL_EV_HIDHOST_INFO,
+                                                       sizeof(ev), &ev, -1);
+}
+
+static int uhid_create(struct hid_device *dev)
+{
+       GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_NVAL;
+       GIOChannel *io;
+       struct uhid_event ev;
+
+       dev->uhid_fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
+       if (dev->uhid_fd < 0) {
+               error("Failed to open uHID device: %s", strerror(errno));
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_NO_HID);
+               return -errno;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_CREATE;
+       strcpy((char *) ev.u.create.name, "bluez-input-device");
+       ev.u.create.bus = BUS_BLUETOOTH;
+       ev.u.create.vendor = dev->vendor;
+       ev.u.create.product = dev->product;
+       ev.u.create.version = dev->version;
+       ev.u.create.country = dev->country;
+       ev.u.create.rd_size = dev->rd_size;
+       ev.u.create.rd_data = dev->rd_data;
+
+       if (write(dev->uhid_fd, &ev, sizeof(ev)) < 0) {
+               error("Failed to create uHID device: %s", strerror(errno));
+               close(dev->uhid_fd);
+               dev->uhid_fd = -1;
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_NO_HID);
+               return -errno;
+       }
+
+       io = g_io_channel_unix_new(dev->uhid_fd);
+       g_io_channel_set_encoding(io, NULL, NULL);
+       dev->uhid_watch_id = g_io_add_watch(io, cond, uhid_event_cb, dev);
+       g_io_channel_unref(io);
+
+       bt_hid_set_info(dev);
+
+       return 0;
+}
+
+static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
+                                                       gpointer user_data)
+{
+       struct hid_device *dev = user_data;
+
+       DBG("");
+
+       if (conn_err) {
+               error("%s", conn_err->message);
+               goto failed;
+       }
+
+       if (uhid_create(dev) < 0)
+               goto failed;
+
+       dev->intr_watch = g_io_add_watch(dev->intr_io,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               intr_watch_cb, dev);
+
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
+
+       return;
+
+failed:
+       hid_device_free(dev);
+}
+
+static void control_connect_cb(GIOChannel *chan, GError *conn_err,
+                                                       gpointer user_data)
+{
+       struct hid_device *dev = user_data;
+       GError *err = NULL;
+
+       DBG("");
+
+       if (conn_err) {
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+               error("%s", conn_err->message);
+               goto failed;
+       }
+
+       /* Connect to the HID interrupt channel */
+       dev->intr_io = bt_io_connect(interrupt_connect_cb, dev, NULL, &err,
+                                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                                       BT_IO_OPT_DEST_BDADDR, &dev->dst,
+                                       BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+       if (!dev->intr_io) {
+               error("%s", err->message);
+               g_error_free(err);
+               goto failed;
+       }
+
+       dev->ctrl_watch = g_io_add_watch(dev->ctrl_io,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               ctrl_watch_cb, dev);
+
+       return;
+
+failed:
+       hid_device_free(dev);
+}
+
+static void hid_sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+       struct hid_device *dev = data;
+       sdp_list_t *list;
+       GError *gerr = NULL;
+
+       DBG("");
+
+       if (err < 0) {
+               error("Unable to get SDP record: %s", strerror(-err));
+               goto fail;
+       }
+
+       if (!recs || !recs->data) {
+               error("No SDP records found");
+               goto fail;
+       }
+
+       for (list = recs; list != NULL; list = list->next) {
+               sdp_record_t *rec = list->data;
+               sdp_data_t *data;
+
+               data = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
+               if (data)
+                       dev->vendor = data->val.uint16;
+
+               data = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
+               if (data)
+                       dev->product = data->val.uint16;
+
+               data = sdp_data_get(rec, SDP_ATTR_VERSION);
+               if (data)
+                       dev->version = data->val.uint16;
+
+               data = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
+               if (data)
+                       dev->country = data->val.uint8;
+
+               data = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
+               if (data)
+                       dev->subclass = data->val.uint8;
+
+               data = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
+               if (data)
+                       dev->boot_dev = data->val.uint8;
+
+               data = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
+               if (data) {
+                       if (!SDP_IS_SEQ(data->dtd))
+                               goto fail;
+
+                       /* First HIDDescriptor */
+                       data = data->val.dataseq;
+                       if (!SDP_IS_SEQ(data->dtd))
+                               goto fail;
+
+                       /* ClassDescriptorType */
+                       data = data->val.dataseq;
+                       if (data->dtd != SDP_UINT8)
+                               goto fail;
+
+                       /* ClassDescriptorData */
+                       data = data->next;
+                       if (!data || !SDP_IS_TEXT_STR(data->dtd))
+                               goto fail;
+
+                       dev->rd_size = data->unitSize;
+                       dev->rd_data = g_memdup(data->val.str, data->unitSize);
+               }
+       }
+
+       if (dev->ctrl_io) {
+               if (uhid_create(dev) < 0)
+                       goto fail;
+               return;
+       }
+
+       dev->ctrl_io = bt_io_connect(control_connect_cb, dev, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                                       BT_IO_OPT_DEST_BDADDR, &dev->dst,
+                                       BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               goto fail;
+       }
+
+       return;
+
+fail:
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+       hid_device_free(dev);
+}
+
+static uint8_t bt_hid_connect(struct hal_cmd_hidhost_connect *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       char addr[18];
+       bdaddr_t dst;
+       GSList *l;
+       uuid_t uuid;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (l)
+               return HAL_STATUS_FAILED;
+
+       dev = g_new0(struct hid_device, 1);
+       bacpy(&dev->dst, &dst);
+       dev->uhid_fd = -1;
+
+       ba2str(&dev->dst, addr);
+       DBG("connecting to %s", addr);
+
+       bt_string2uuid(&uuid, HID_UUID);
+       if (bt_search_service(&adapter_addr, &dev->dst, &uuid,
+                                       hid_sdp_search_cb, dev, NULL) < 0) {
+               error("Failed to search sdp details");
+               hid_device_free(dev);
+               return HAL_STATUS_FAILED;
+       }
+
+       devices = g_slist_append(devices, dev);
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTING);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_disconnect(struct hal_cmd_hidhost_disconnect *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       /* Wait either channels to HUP */
+       if (dev->intr_io)
+               g_io_channel_shutdown(dev->intr_io, TRUE, NULL);
+
+       if (dev->ctrl_io)
+               g_io_channel_shutdown(dev->ctrl_io, TRUE, NULL);
+
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTING);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_virtual_unplug(struct hal_cmd_hidhost_virtual_unplug *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       uint8_t hdr;
+       int fd;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       if (!(dev->ctrl_io))
+               return HAL_STATUS_FAILED;
+
+       hdr = HID_MSG_CONTROL | HID_VIRTUAL_CABLE_UNPLUG;
+
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, &hdr, sizeof(hdr)) < 0) {
+               error("error writing virtual unplug command: %s (%d)",
+                                               strerror(errno), errno);
+               return HAL_STATUS_FAILED;
+       }
+
+       /* Wait either channels to HUP */
+       if (dev->intr_io)
+               g_io_channel_shutdown(dev->intr_io, TRUE, NULL);
+
+       if (dev->ctrl_io)
+               g_io_channel_shutdown(dev->ctrl_io, TRUE, NULL);
+
+       bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTING);
+
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_info(struct hal_cmd_hidhost_set_info *cmd, uint16_t len)
+{
+       /* Data from hal_cmd_hidhost_set_info is usefull only when we create
+        * UHID device. Once device is created all the transactions will be
+        * done through the fd. There is no way to use this information
+        * once device is created with HID internals. */
+       DBG("Not supported");
+
+       return HAL_STATUS_UNSUPPORTED;
+}
+
+static uint8_t bt_hid_get_protocol(struct hal_cmd_hidhost_get_protocol *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       int fd;
+       uint8_t hdr;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       if (dev->boot_dev)
+               return HAL_STATUS_UNSUPPORTED;
+
+       hdr = HID_MSG_GET_PROTOCOL | cmd->mode;
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, &hdr, sizeof(hdr)) < 0) {
+               error("error writing device_get_protocol: %s (%d)",
+                                               strerror(errno), errno);
+               return HAL_STATUS_FAILED;
+       }
+
+       dev->last_hid_msg = HID_MSG_GET_PROTOCOL;
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_set_protocol(struct hal_cmd_hidhost_set_protocol *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       int fd;
+       uint8_t hdr;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       if (dev->boot_dev)
+               return HAL_STATUS_UNSUPPORTED;
+
+       hdr = HID_MSG_SET_PROTOCOL | cmd->mode;
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, &hdr, sizeof(hdr)) < 0) {
+               error("error writing device_set_protocol: %s (%d)",
+                                               strerror(errno), errno);
+               return HAL_STATUS_FAILED;
+       }
+
+       dev->last_hid_msg = HID_MSG_SET_PROTOCOL;
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_get_report(struct hal_cmd_hidhost_get_report *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       int fd;
+       uint8_t *req;
+       uint8_t req_size;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+       req_size = (cmd->buf_size > 0) ? 4 : 2;
+       req = g_try_malloc0(req_size);
+       if (!req)
+               return HAL_STATUS_NOMEM;
+
+       req[0] = HID_MSG_GET_REPORT | cmd->type;
+       req[1] = cmd->id;
+
+       if (cmd->buf_size > 0) {
+               req[0] = req[0] | HID_GET_REPORT_SIZE_FIELD;
+               bt_put_le16(cmd->buf_size, &req[2]);
+       }
+
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, req, req_size) < 0) {
+               error("error writing hid_get_report: %s (%d)",
+                                               strerror(errno), errno);
+               g_free(req);
+               return HAL_STATUS_FAILED;
+       }
+
+       dev->last_hid_msg = HID_MSG_GET_REPORT;
+       g_free(req);
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_set_report(struct hal_cmd_hidhost_set_report *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       int i, fd;
+       uint8_t *req;
+       uint8_t req_size;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       if (!(dev->ctrl_io))
+               return HAL_STATUS_FAILED;
+
+       req_size = 1 + (cmd->len / 2);
+       req = g_try_malloc0(req_size);
+       if (!req)
+               return HAL_STATUS_NOMEM;
+
+       req[0] = HID_MSG_SET_REPORT | cmd->type;
+       /* Report data coming to HAL is in ascii format, HAL sends
+        * data in hex to daemon, so convert to binary. */
+       for (i = 0; i < (req_size - 1); i++)
+               sscanf((char *) &(cmd->data)[i * 2], "%hhx", &(req + 1)[i]);
+
+       fd = g_io_channel_unix_get_fd(dev->ctrl_io);
+
+       if (write(fd, req, req_size) < 0) {
+               error("error writing hid_set_report: %s (%d)",
+                                               strerror(errno), errno);
+               g_free(req);
+               return HAL_STATUS_FAILED;
+       }
+
+       dev->last_hid_msg = HID_MSG_SET_REPORT;
+       g_free(req);
+       return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_hid_send_data(struct hal_cmd_hidhost_send_data *cmd,
+                                                               uint16_t len)
+{
+       struct hid_device *dev;
+       GSList *l;
+       bdaddr_t dst;
+       int i, fd;
+       uint8_t *req;
+       uint8_t req_size;
+
+       DBG("");
+
+       if (len < sizeof(*cmd))
+               return HAL_STATUS_INVALID;
+
+       android2bdaddr(&cmd->bdaddr, &dst);
+
+       l = g_slist_find_custom(devices, &dst, device_cmp);
+       if (!l)
+               return HAL_STATUS_FAILED;
+
+       dev = l->data;
+
+       if (!(dev->intr_io))
+               return HAL_STATUS_FAILED;
+
+       req_size = 1 + (cmd->len / 2);
+       req = g_try_malloc0(req_size);
+       if (!req)
+               return HAL_STATUS_NOMEM;
+
+       req[0] = HID_MSG_DATA | HID_DATA_TYPE_OUTPUT;
+       /* Report data coming to HAL is in ascii format, HAL sends
+        * data in hex to daemon, so convert to binary. */
+       for (i = 0; i < (req_size - 1); i++)
+               sscanf((char *) &(cmd->data)[i * 2], "%hhx", &(req + 1)[i]);
+
+       fd = g_io_channel_unix_get_fd(dev->intr_io);
+
+       if (write(fd, req, req_size) < 0) {
+               error("error writing data to HID device: %s (%d)",
+                                               strerror(errno), errno);
+               g_free(req);
+               return HAL_STATUS_FAILED;
+       }
+
+       g_free(req);
+       return HAL_STATUS_SUCCESS;
+}
+
+void bt_hid_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
+{
+       uint8_t status = HAL_STATUS_FAILED;
+
+       switch (opcode) {
+       case HAL_OP_HIDHOST_CONNECT:
+               status = bt_hid_connect(buf, len);
+               break;
+       case HAL_OP_HIDHOST_DISCONNECT:
+               status = bt_hid_disconnect(buf, len);
+               break;
+       case HAL_OP_HIDHOST_VIRTUAL_UNPLUG:
+               status = bt_hid_virtual_unplug(buf, len);
+               break;
+       case HAL_OP_HIDHOST_SET_INFO:
+               status = bt_hid_info(buf, len);
+               break;
+       case HAL_OP_HIDHOST_GET_PROTOCOL:
+               status = bt_hid_get_protocol(buf, len);
+               break;
+       case HAL_OP_HIDHOST_SET_PROTOCOL:
+               status = bt_hid_set_protocol(buf, len);
+               break;
+       case HAL_OP_HIDHOST_GET_REPORT:
+               status = bt_hid_get_report(buf, len);
+               break;
+       case HAL_OP_HIDHOST_SET_REPORT:
+               status = bt_hid_set_report(buf, len);
+               break;
+       case HAL_OP_HIDHOST_SEND_DATA:
+               status = bt_hid_send_data(buf, len);
+               break;
+       default:
+               DBG("Unhandled command, opcode 0x%x", opcode);
+               break;
+       }
+
+       ipc_send_rsp(sk, HAL_SERVICE_ID_HIDHOST, status);
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+       struct hid_device *dev;
+       bdaddr_t src, dst;
+       char address[18];
+       uint16_t psm;
+       GError *gerr = NULL;
+       GSList *l;
+       uuid_t uuid;
+
+       if (err) {
+               error("%s", err->message);
+               return;
+       }
+
+       bt_io_get(chan, &gerr,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_PSM, &psm,
+                       BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("%s", gerr->message);
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               g_error_free(gerr);
+               return;
+       }
+
+       ba2str(&dst, address);
+       DBG("Incoming connection from %s on PSM %d", address, psm);
+
+       switch (psm) {
+       case L2CAP_PSM_HIDP_CTRL:
+               l = g_slist_find_custom(devices, &dst, device_cmp);
+               if (l)
+                       return;
+
+               dev = g_new0(struct hid_device, 1);
+               bacpy(&dev->dst, &dst);
+               dev->ctrl_io = g_io_channel_ref(chan);
+               dev->uhid_fd = -1;
+
+               bt_string2uuid(&uuid, HID_UUID);
+               if (bt_search_service(&src, &dev->dst, &uuid,
+                                       hid_sdp_search_cb, dev, NULL) < 0) {
+                       error("failed to search sdp details");
+                       hid_device_free(dev);
+                       return;
+               }
+
+               devices = g_slist_append(devices, dev);
+
+               dev->ctrl_watch = g_io_add_watch(dev->ctrl_io,
+                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                       ctrl_watch_cb, dev);
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTING);
+               break;
+
+       case L2CAP_PSM_HIDP_INTR:
+               l = g_slist_find_custom(devices, &dst, device_cmp);
+               if (!l)
+                       return;
+
+               dev = l->data;
+               dev->intr_io = g_io_channel_ref(chan);
+               dev->intr_watch = g_io_add_watch(dev->intr_io,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               intr_watch_cb, dev);
+               bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
+               break;
+       }
+}
+
+bool bt_hid_register(int sk, const bdaddr_t *addr)
+{
+       GError *err = NULL;
+
+       DBG("");
+
+       bacpy(&adapter_addr, addr);
+
+       ctrl_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                               BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+       if (!ctrl_io) {
+               error("Failed to listen on ctrl channel: %s", err->message);
+               g_error_free(err);
+               return false;
+       }
+
+       intr_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                               BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+       if (!intr_io) {
+               error("Failed to listen on intr channel: %s", err->message);
+               g_io_channel_unref(ctrl_io);
+               g_error_free(err);
+               return false;
+       }
+
+       notification_sk = sk;
+
+       return true;
+}
+
+void bt_hid_unregister(void)
+{
+       DBG("");
+
+       notification_sk = -1;
+
+       if (ctrl_io) {
+               g_io_channel_shutdown(ctrl_io, TRUE, NULL);
+               g_io_channel_unref(ctrl_io);
+               ctrl_io = NULL;
+       }
+
+       if (intr_io) {
+               g_io_channel_shutdown(intr_io, TRUE, NULL);
+               g_io_channel_unref(intr_io);
+               intr_io = NULL;
+       }
+}
diff --git a/android/hidhost.h b/android/hidhost.h
new file mode 100644 (file)
index 0000000..688086a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void bt_hid_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
+
+bool bt_hid_register(int sk, const bdaddr_t *addr);
+void bt_hid_unregister(void);
diff --git a/android/ipc.c b/android/ipc.c
new file mode 100644 (file)
index 0000000..729f157
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include "hal-msg.h"
+#include "ipc.h"
+#include "log.h"
+
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+                                                       void *param, int fd)
+{
+       struct msghdr msg;
+       struct iovec iv[2];
+       struct hal_hdr m;
+       char cmsgbuf[CMSG_SPACE(sizeof(int))];
+       struct cmsghdr *cmsg;
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&m, 0, sizeof(m));
+
+       m.service_id = service_id;
+       m.opcode = opcode;
+       m.len = len;
+
+       iv[0].iov_base = &m;
+       iv[0].iov_len = sizeof(m);
+
+       iv[1].iov_base = param;
+       iv[1].iov_len = len;
+
+       msg.msg_iov = iv;
+       msg.msg_iovlen = 2;
+
+       if (fd >= 0) {
+               msg.msg_control = cmsgbuf;
+               msg.msg_controllen = sizeof(cmsgbuf);
+
+               cmsg = CMSG_FIRSTHDR(&msg);
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_RIGHTS;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+               /* Initialize the payload */
+               memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+       }
+
+       if (sendmsg(sk, &msg, 0) < 0) {
+               error("IPC send failed, terminating :%s", strerror(errno));
+               raise(SIGTERM);
+       }
+}
+
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status)
+{
+       struct hal_status s;
+
+       s.code = status;
+
+       ipc_send(sk, service_id, HAL_OP_STATUS, sizeof(s), &s, -1);
+}
diff --git a/android/ipc.h b/android/ipc.h
new file mode 100644 (file)
index 0000000..cf0f3d6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+                                                       void *param, int fd);
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status);
index f75b0a8..a4f5e84 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #include <glib.h>
 
 #include "log.h"
+#include "src/sdpd.h"
+
+#include "lib/bluetooth.h"
+
+#include "bluetooth.h"
+#include "socket.h"
+#include "hidhost.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "a2dp.h"
+#include "pan.h"
+
+/* TODO: Consider to remove PLATFORM_SDKVERSION check if requirement
+*  for minimal Android platform version increases. */
+#if defined(ANDROID) && PLATFORM_SDK_VERSION >= 18
+#include <sys/capability.h>
+#endif
 
+#define STARTUP_GRACE_SECONDS 5
 #define SHUTDOWN_GRACE_SECONDS 10
 
+static guint bluetooth_start_timeout = 0;
+
+static bdaddr_t adapter_bdaddr;
+
 static GMainLoop *event_loop;
 
+static GIOChannel *hal_cmd_io = NULL;
+static GIOChannel *hal_notif_io = NULL;
+
+static bool services[HAL_SERVICE_ID_MAX + 1] = { false };
+
+static void service_register(void *buf, uint16_t len)
+{
+       struct hal_cmd_register_module *m = buf;
+       int sk = g_io_channel_unix_get_fd(hal_notif_io);
+
+       if (m->service_id > HAL_SERVICE_ID_MAX || services[m->service_id])
+               goto failed;
+
+       switch (m->service_id) {
+       case HAL_SERVICE_ID_BLUETOOTH:
+               if (!bt_bluetooth_register(sk))
+                       goto failed;
+
+               break;
+       case HAL_SERVICE_ID_SOCK:
+               if (!bt_socket_register(sk, &adapter_bdaddr))
+                       goto failed;
+
+               break;
+       case HAL_SERVICE_ID_HIDHOST:
+               if (!bt_hid_register(sk, &adapter_bdaddr))
+                       goto failed;
+
+               break;
+       case HAL_SERVICE_ID_A2DP:
+               if (!bt_a2dp_register(sk, &adapter_bdaddr))
+                       goto failed;
+
+               break;
+       case HAL_SERVICE_ID_PAN:
+               if (!bt_pan_register(sk, &adapter_bdaddr))
+                       goto failed;
+
+               break;
+       default:
+               DBG("service %u not supported", m->service_id);
+               goto failed;
+       }
+
+       services[m->service_id] = true;
+
+       ipc_send(g_io_channel_unix_get_fd(hal_cmd_io), HAL_SERVICE_ID_CORE,
+                                       HAL_OP_REGISTER_MODULE, 0, NULL, -1);
+
+       info("Service ID=%u registered", m->service_id);
+       return;
+failed:
+       ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
+                               HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+}
+
+static void service_unregister(void *buf, uint16_t len)
+{
+       struct hal_cmd_unregister_module *m = buf;
+
+       if (m->service_id > HAL_SERVICE_ID_MAX || !services[m->service_id])
+               goto failed;
+
+       switch (m->service_id) {
+       case HAL_SERVICE_ID_BLUETOOTH:
+               bt_bluetooth_unregister();
+               break;
+       case HAL_SERVICE_ID_SOCK:
+               bt_socket_unregister();
+               break;
+       case HAL_SERVICE_ID_HIDHOST:
+               bt_hid_unregister();
+               break;
+       case HAL_SERVICE_ID_A2DP:
+               bt_a2dp_unregister();
+               break;
+       case HAL_SERVICE_ID_PAN:
+               bt_pan_unregister();
+               break;
+       default:
+               /* This would indicate bug in HAL, as unregister should not be
+                * called in init failed */
+               DBG("service %u not supported", m->service_id);
+               goto failed;
+       }
+
+       services[m->service_id] = false;
+
+       ipc_send(g_io_channel_unix_get_fd(hal_cmd_io), HAL_SERVICE_ID_CORE,
+                                       HAL_OP_UNREGISTER_MODULE, 0, NULL, -1);
+
+       info("Service ID=%u unregistered", m->service_id);
+       return;
+failed:
+       ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
+                               HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+}
+
+static void handle_service_core(uint8_t opcode, void *buf, uint16_t len)
+{
+       switch (opcode) {
+       case HAL_OP_REGISTER_MODULE:
+               service_register(buf, len);
+               break;
+       case HAL_OP_UNREGISTER_MODULE:
+               service_unregister(buf, len);
+               break;
+       default:
+               ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
+                               HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+               break;
+       }
+}
+
+static void bluetooth_stopped(void)
+{
+       g_main_loop_quit(event_loop);
+}
+
 static gboolean quit_eventloop(gpointer user_data)
 {
        g_main_loop_quit(event_loop);
+       return FALSE;
+}
+
+static void stop_bluetooth(void)
+{
+       static bool __stop = false;
+
+       if (__stop)
+               return;
+
+       __stop = true;
+
+       if (!bt_bluetooth_stop(bluetooth_stopped)) {
+               g_main_loop_quit(event_loop);
+               return;
+       }
+
+       g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS, quit_eventloop, NULL);
+}
+
+static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       char buf[BLUEZ_HAL_MTU];
+       struct hal_hdr *msg = (void *) buf;
+       ssize_t ret;
+       int fd;
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               info("HAL command socket closed, terminating");
+               goto fail;
+       }
+
+       fd = g_io_channel_unix_get_fd(io);
+
+       ret = read(fd, buf, sizeof(buf));
+       if (ret < 0) {
+               error("HAL command read failed, terminating (%s)",
+                                                       strerror(errno));
+               goto fail;
+       }
+
+       if (ret < (ssize_t) sizeof(*msg)) {
+               error("HAL command too small, terminating (%zd)", ret);
+               goto fail;
+       }
+
+       if (ret != (ssize_t) (sizeof(*msg) + msg->len)) {
+               error("Malformed HAL command (%zd bytes), terminating", ret);
+               goto fail;
+       }
+
+       DBG("service_id %u opcode %u len %u", msg->service_id, msg->opcode,
+                                                               msg->len);
+
+       if (msg->service_id > HAL_SERVICE_ID_MAX ||
+                                               !services[msg->service_id]) {
+               error("HAL command for unregistered service %u, terminating",
+                                                       msg->service_id);
+               goto fail;
+       }
+
+       switch (msg->service_id) {
+       case HAL_SERVICE_ID_CORE:
+               handle_service_core(msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_BLUETOOTH:
+               bt_bluetooth_handle_cmd(fd, msg->opcode, msg->payload,
+                                                               msg->len);
+               break;
+       case HAL_SERVICE_ID_HIDHOST:
+               bt_hid_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_SOCK:
+               bt_sock_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_A2DP:
+               bt_a2dp_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
+               break;
+       case HAL_SERVICE_ID_PAN:
+               bt_pan_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
+               break;
+       default:
+               ipc_send_rsp(fd, msg->service_id, HAL_STATUS_FAILED);
+               break;
+       }
+
+       return TRUE;
+
+fail:
+       stop_bluetooth();
+       return FALSE;
+}
+
+static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       info("HAL notification socket closed, terminating");
+       stop_bluetooth();
+
+       return FALSE;
+}
+
+static GIOChannel *connect_hal(GIOFunc connect_cb)
+{
+       struct sockaddr_un addr;
+       GIOCondition cond;
+       GIOChannel *io;
+       int sk;
+
+       sk = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+       if (sk < 0) {
+               error("Failed to create socket: %d (%s)", errno,
+                                                       strerror(errno));
+               return NULL;
+       }
+
+       io = g_io_channel_unix_new(sk);
+
+       g_io_channel_set_close_on_unref(io, TRUE);
+       g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+
+       memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+
+       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               error("Failed to connect HAL socket: %d (%s)", errno,
+                                                       strerror(errno));
+               g_io_channel_unref(io);
+               return NULL;
+       }
+
+       cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+       g_io_add_watch(io, cond, connect_cb, NULL);
+
+       return io;
+}
+
+static gboolean notif_connect_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       DBG("");
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               stop_bluetooth();
+               return FALSE;
+       }
+
+       cond = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+       g_io_add_watch(io, cond, notif_watch_cb, NULL);
+
+       cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+       g_io_add_watch(hal_cmd_io, cond, cmd_watch_cb, NULL);
+
+       info("Successfully connected to HAL");
 
        return FALSE;
 }
 
-static void sig_term(int sig)
+static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       DBG("");
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               stop_bluetooth();
+               return FALSE;
+       }
+
+       hal_notif_io = connect_hal(notif_connect_cb);
+       if (!hal_notif_io) {
+               error("Cannot connect to HAL, terminating");
+               stop_bluetooth();
+       }
+
+       return FALSE;
+}
+
+static void adapter_ready(int err, const bdaddr_t *addr)
+{
+       if (err < 0) {
+               error("Adapter initialization failed: %s", strerror(-err));
+               exit(EXIT_FAILURE);
+       }
+
+       bacpy(&adapter_bdaddr, addr);
+
+       if (bluetooth_start_timeout > 0) {
+               g_source_remove(bluetooth_start_timeout);
+               bluetooth_start_timeout = 0;
+       }
+
+       info("Adapter initialized");
+
+       hal_cmd_io = connect_hal(cmd_connect_cb);
+       if (!hal_cmd_io) {
+               error("Cannot connect to HAL, terminating");
+               stop_bluetooth();
+       }
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
 {
        static bool __terminated = false;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
 
-       if (!__terminated) {
-               g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
-                                               quit_eventloop, NULL);
+       switch (si.ssi_signo) {
+       case SIGINT:
+       case SIGTERM:
+               if (!__terminated) {
+                       info("Terminating");
+                       stop_bluetooth();
+               }
+
+               __terminated = true;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
        }
 
-       __terminated = true;
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
 }
 
 static gboolean option_version = FALSE;
+static gint option_index = -1;
 
 static GOptionEntry options[] = {
        { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
                                "Show version information and exit", NULL },
+       { "index", 'i', 0, G_OPTION_ARG_INT, &option_index,
+                               "Use specified controller", "INDEX"},
        { NULL }
 };
 
+static void cleanup_hal_connection(void)
+{
+       if (hal_cmd_io) {
+               g_io_channel_shutdown(hal_cmd_io, TRUE, NULL);
+               g_io_channel_unref(hal_cmd_io);
+               hal_cmd_io = NULL;
+       }
+
+       if (hal_notif_io) {
+               g_io_channel_shutdown(hal_notif_io, TRUE, NULL);
+               g_io_channel_unref(hal_notif_io);
+               hal_notif_io = NULL;
+       }
+}
+
+static bool set_capabilities(void)
+{
+#if defined(ANDROID)
+       struct __user_cap_header_struct header;
+       struct __user_cap_data_struct cap;
+
+       header.version = _LINUX_CAPABILITY_VERSION;
+       header.pid = 0;
+
+       cap.effective = cap.permitted =
+               CAP_TO_MASK(CAP_NET_ADMIN) |
+               CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+       cap.inheritable = 0;
+
+       /* TODO: Move to cap_set_proc once bionic support it */
+       if (capset(&header, &cap) < 0) {
+               error("%s: capset(): %s", __func__, strerror(errno));
+               return false;
+       }
+
+       /* TODO: Move to cap_get_proc once bionic support it */
+       if (capget(&header, &cap) < 0) {
+               error("%s: capget(): %s", __func__, strerror(errno));
+               return false;
+       }
+
+       DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective,
+                                       cap.permitted, cap.inheritable);
+
+#endif
+       return true;
+}
+
 int main(int argc, char *argv[])
 {
        GOptionContext *context;
        GError *err = NULL;
-       struct sigaction sa;
+       guint signal;
+
+       /* Core Service (ID=0) should always be considered registered */
+       services[0] = true;
 
        context = g_option_context_new(NULL);
        g_option_context_add_main_entries(context, options, NULL);
@@ -94,19 +555,42 @@ int main(int argc, char *argv[])
        }
 
        event_loop = g_main_loop_new(NULL, FALSE);
+       signal = setup_signalfd();
+       if (!signal)
+               return EXIT_FAILURE;
+
+       __btd_log_init("*", 0);
+
+       if (!set_capabilities())
+               return EXIT_FAILURE;
 
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_handler = sig_term;
-       sigaction(SIGINT, &sa, NULL);
-       sigaction(SIGTERM, &sa, NULL);
+       bluetooth_start_timeout = g_timeout_add_seconds(STARTUP_GRACE_SECONDS,
+                                                       quit_eventloop, NULL);
+       if (bluetooth_start_timeout == 0) {
+               error("Failed to init startup timeout");
+               return EXIT_FAILURE;
+       }
+
+       if (!bt_bluetooth_start(option_index, adapter_ready))
+               return EXIT_FAILURE;
+
+       /* Use params: mtu = 0, flags = 0 */
+       start_sdp_server(0, 0);
 
        DBG("Entering main loop");
 
        g_main_loop_run(event_loop);
 
+       g_source_remove(signal);
+
+       cleanup_hal_connection();
+       stop_sdp_server();
+       bt_bluetooth_cleanup();
        g_main_loop_unref(event_loop);
 
        info("Exit");
 
+       __btd_log_cleanup();
+
        return EXIT_SUCCESS;
 }
diff --git a/android/pan.c b/android/pan.c
new file mode 100644 (file)
index 0000000..46b3700
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "log.h"
+#include "pan.h"
+#include "hal-msg.h"
+#include "ipc.h"
+
+static int notification_sk = -1;
+
+static uint8_t bt_pan_enable(struct hal_cmd_pan_enable *cmd, uint16_t len)
+{
+       DBG("Not Implemented");
+
+       return HAL_STATUS_FAILED;
+}
+
+static uint8_t bt_pan_get_role(void *cmd, uint16_t len)
+{
+       DBG("Not Implemented");
+
+       return HAL_STATUS_FAILED;
+}
+
+static uint8_t bt_pan_connect(struct hal_cmd_pan_connect *cmd, uint16_t len)
+{
+       DBG("Not Implemented");
+
+       return HAL_STATUS_FAILED;
+}
+
+static uint8_t bt_pan_disconnect(struct hal_cmd_pan_connect *cmd, uint16_t len)
+{
+       DBG("Not Implemented");
+
+       return HAL_STATUS_FAILED;
+}
+
+void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
+{
+       uint8_t status = HAL_STATUS_FAILED;
+
+       switch (opcode) {
+       case HAL_OP_PAN_ENABLE:
+               status = bt_pan_enable(buf, len);
+               break;
+       case HAL_OP_PAN_GET_ROLE:
+               status = bt_pan_get_role(buf, len);
+               break;
+       case HAL_OP_PAN_CONNECT:
+               status = bt_pan_connect(buf, len);
+               break;
+       case HAL_OP_PAN_DISCONNECT:
+               status = bt_pan_disconnect(buf, len);
+               break;
+       default:
+               DBG("Unhandled command, opcode 0x%x", opcode);
+               break;
+       }
+
+       ipc_send_rsp(sk, HAL_SERVICE_ID_PAN, status);
+}
+
+bool bt_pan_register(int sk, const bdaddr_t *addr)
+{
+       DBG("");
+
+       notification_sk = sk;
+
+       return true;
+}
+
+void bt_pan_unregister(void)
+{
+       DBG("");
+
+       notification_sk = -1;
+}
diff --git a/android/pan.h b/android/pan.h
new file mode 100644 (file)
index 0000000..2430378
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
+
+bool bt_pan_register(int sk, const bdaddr_t *addr);
+void bt_pan_unregister(void);
diff --git a/android/socket.c b/android/socket.c
new file mode 100644 (file)
index 0000000..c283c5f
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <stdbool.h>
+
+#include "lib/bluetooth.h"
+#include "log.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+#include "ipc.h"
+#include "socket.h"
+
+
+static int handle_listen(void *buf)
+{
+       DBG("Not implemented");
+
+       return -1;
+}
+
+static int handle_connect(void *buf)
+{
+       DBG("Not implemented");
+
+       return -1;
+}
+
+void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
+{
+       int fd;
+
+       switch (opcode) {
+       case HAL_OP_SOCK_LISTEN:
+               fd = handle_listen(buf);
+               if (fd < 0)
+                       break;
+
+               ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+               return;
+       case HAL_OP_SOCK_CONNECT:
+               fd = handle_connect(buf);
+               if (fd < 0)
+                       break;
+
+               ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+               return;
+       default:
+               DBG("Unhandled command, opcode 0x%x", opcode);
+               break;
+       }
+
+       ipc_send_rsp(sk, HAL_SERVICE_ID_SOCK, HAL_STATUS_FAILED);
+}
+
+bool bt_socket_register(int sk, const bdaddr_t *addr)
+{
+       DBG("");
+
+       return true;
+}
+
+void bt_socket_unregister(void)
+{
+       DBG("");
+}
diff --git a/android/socket.h b/android/socket.h
new file mode 100644 (file)
index 0000000..7aa5574
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
+
+bool bt_socket_register(int sk, const bdaddr_t *addr);
+void bt_socket_unregister(void);
diff --git a/android/system-emulator.c b/android/system-emulator.c
new file mode 100644 (file)
index 0000000..24f2741
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <libgen.h>
+#include <sys/poll.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "monitor/mainloop.h"
+
+static char exec_dir[PATH_MAX + 1];
+
+static pid_t daemon_pid = -1;
+
+static void ctl_start(void)
+{
+       char prg_name[PATH_MAX + 1];
+       char *prg_argv[3];
+       char *prg_envp[3];
+       pid_t pid;
+
+       snprintf(prg_name, sizeof(prg_name), "%s/%s", exec_dir, "bluetoothd");
+
+       prg_argv[0] = "/usr/bin/valgrind";
+       prg_argv[1] = prg_name;
+       prg_argv[2] = NULL;
+
+       prg_envp[0] = "G_SLICE=always-malloc";
+       prg_envp[1] = "G_DEBUG=gc-friendly";
+       prg_envp[2] = NULL;
+
+       printf("Starting %s\n", prg_name);
+
+       pid = fork();
+       if (pid < 0) {
+               perror("Failed to fork new process");
+               return;
+       }
+
+       if (pid == 0) {
+               execve(prg_argv[0], prg_argv, prg_envp);
+               exit(0);
+       }
+
+       printf("New process %d created\n", pid);
+
+       daemon_pid = pid;
+}
+
+static void system_socket_callback(int fd, uint32_t events, void *user_data)
+{
+       char buf[4096];
+       ssize_t len;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0)
+               return;
+
+       printf("Received %s\n", buf);
+
+       if (strcmp(buf, "ctl.start=bluetoothd"))
+               return;
+
+       if (daemon_pid > 0)
+               return;
+
+       ctl_start();
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               mainloop_quit();
+               break;
+       case SIGCHLD:
+               while (1) {
+                       pid_t pid;
+                       int status;
+
+                       pid = waitpid(WAIT_ANY, &status, WNOHANG);
+                       if (pid < 0 || pid == 0)
+                               break;
+
+                       printf("Process %d terminated with status=%d\n",
+                                                               pid, status);
+
+                       if (pid == daemon_pid)
+                               daemon_pid = -1;
+               }
+               break;
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       static const char SYSTEM_SOCKET_PATH[] = "\0android_system";
+
+       sigset_t mask;
+       struct sockaddr_un addr;
+       int fd;
+
+       mainloop_init();
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGCHLD);
+
+       mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+       printf("Android system emulator ver %s\n", VERSION);
+
+       snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0]));
+
+       fd = socket(PF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               perror("Failed to create system socket");
+               return EXIT_FAILURE;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       memcpy(addr.sun_path, SYSTEM_SOCKET_PATH, sizeof(SYSTEM_SOCKET_PATH));
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind system socket");
+               close(fd);
+               return EXIT_FAILURE;
+       }
+
+       mainloop_add_fd(fd, EPOLLIN, system_socket_callback, NULL, NULL);
+
+       return mainloop_run();
+}
similarity index 53%
rename from android/log.c
rename to android/utils.h
index ce07b82..5b009bc 100644 (file)
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <sys/uio.h>
-
-#include <glib.h>
-
-void info(const char *format, ...)
-{
-       va_list ap;
-
-       va_start(ap, format);
-
-       vfprintf(stdout, format, ap);
-       fprintf(stdout, "\n");
-
-       va_end(ap);
-}
-
-void warn(const char *format, ...)
-{
-       va_list ap;
-
-       va_start(ap, format);
-
-       vfprintf(stderr, format, ap);
-       fprintf(stderr, "\n");
-
-       va_end(ap);
-}
-
-void error(const char *format, ...)
+static inline void android2bdaddr(const void *buf, bdaddr_t *dst)
 {
-       va_list ap;
-
-       va_start(ap, format);
-
-       vfprintf(stderr, format, ap);
-       fprintf(stderr, "\n");
-
-       va_end(ap);
+       baswap(dst, buf);
 }
 
-void btd_debug(const char *format, ...)
+static inline void bdaddr2android(const bdaddr_t *src, void *buf)
 {
-       va_list ap;
-
-       va_start(ap, format);
-
-       vfprintf(stdout, format, ap);
-       fprintf(stdout, "\n");
-
-       va_end(ap);
+       baswap(buf, src);
 }
index 2bb5b0f..76c63e7 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for bluez 5.10.
+# Generated by GNU Autoconf 2.69 for bluez 5.11.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='bluez'
 PACKAGE_TARNAME='bluez'
-PACKAGE_VERSION='5.10'
-PACKAGE_STRING='bluez 5.10'
+PACKAGE_VERSION='5.11'
+PACKAGE_STRING='bluez 5.11'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1397,7 +1397,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures bluez 5.10 to adapt to many kinds of systems.
+\`configure' configures bluez 5.11 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1467,7 +1467,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of bluez 5.10:";;
+     short | recursive ) echo "Configuration of bluez 5.11:";;
    esac
   cat <<\_ACEOF
 
@@ -1615,7 +1615,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-bluez configure 5.10
+bluez configure 5.11
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1980,7 +1980,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by bluez $as_me 5.10, which was
+It was created by bluez $as_me 5.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2835,7 +2835,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='bluez'
- VERSION='5.10'
+ VERSION='5.11'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -14195,7 +14195,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by bluez $as_me 5.10, which was
+This file was extended by bluez $as_me 5.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14261,7 +14261,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-bluez config.status 5.10
+bluez config.status 5.11
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index b4d3998..949846e 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 5.10)
+AC_INIT(bluez, 5.11)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
                                        tar-pax no-dist-gzip dist-xz])
index c3f5243..1f22fea 100644 (file)
@@ -801,7 +801,7 @@ Properties  string Folder [readonly]
 
                boolean Deleted [writeonly]
 
-                       Message read flag
+                       Message deleted flag
 
                boolean Sent [readonly]
 
index da56b5c..0c5836f 100644 (file)
@@ -60,11 +60,19 @@ struct cmd_queue {
        struct cmd *tail;
 };
 
+struct cid_hook {
+       uint16_t cid;
+       bthost_cid_hook_func_t func;
+       void *user_data;
+       struct cid_hook *next;
+};
+
 struct btconn {
        uint16_t handle;
        uint8_t addr_type;
        uint16_t next_cid;
        struct l2conn *l2conns;
+       struct cid_hook *cid_hooks;
        struct btconn *next;
 };
 
@@ -123,6 +131,13 @@ static void btconn_free(struct btconn *conn)
                l2conn_free(l2conn);
        }
 
+       while (conn->cid_hooks) {
+               struct cid_hook *hook = conn->cid_hooks;
+
+               conn->cid_hooks = hook->next;
+               free(hook);
+       }
+
        free(conn);
 }
 
@@ -311,6 +326,42 @@ static uint8_t l2cap_sig_send(struct bthost *bthost, struct btconn *conn,
        return ident;
 }
 
+void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid,
+                               bthost_cid_hook_func_t func, void *user_data)
+{
+       struct cid_hook *hook;
+       struct btconn *conn;
+
+       conn = bthost_find_conn(bthost, handle);
+       if (!conn)
+               return;
+
+       hook = malloc(sizeof(*hook));
+       if (!hook)
+               return;
+
+       memset(hook, 0, sizeof(*hook));
+
+       hook->cid = cid;
+       hook->func = func;
+       hook->user_data = user_data;
+
+       hook->next = conn->cid_hooks;
+       conn->cid_hooks = hook;
+}
+
+void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid,
+                                       const void *data, uint16_t len)
+{
+       struct btconn *conn;
+
+       conn = bthost_find_conn(bthost, handle);
+       if (!conn)
+               return;
+
+       send_acl(bthost, handle, cid, data, len);
+}
+
 bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t code,
                                const void *data, uint16_t len,
                                bthost_l2cap_rsp_cb cb, void *user_data)
@@ -973,11 +1024,24 @@ reject:
                                                        &rej, sizeof(rej));
 }
 
+static struct cid_hook *find_cid_hook(struct btconn *conn, uint16_t cid)
+{
+       struct cid_hook *hook;
+
+       for (hook = conn->cid_hooks; hook != NULL; hook = hook->next) {
+               if (hook->cid == cid)
+                       return hook;
+       }
+
+       return NULL;
+}
+
 static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
 {
        const struct bt_hci_acl_hdr *acl_hdr = data;
        const struct bt_l2cap_hdr *l2_hdr = data + sizeof(*acl_hdr);
        uint16_t handle, cid, acl_len, l2_len;
+       struct cid_hook *hook;
        struct btconn *conn;
        const void *l2_data;
 
@@ -1003,6 +1067,12 @@ static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
 
        cid = le16_to_cpu(l2_hdr->cid);
 
+       hook = find_cid_hook(conn, cid);
+       if (hook) {
+               hook->func(l2_data, l2_len, hook->user_data);
+               return;
+       }
+
        switch (cid) {
        case 0x0001:
                l2cap_sig(bthost, conn, l2_data, l2_len);
index cd5bf1c..32b10f9 100644 (file)
@@ -52,6 +52,15 @@ void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb,
 void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr,
                                                        uint8_t addr_type);
 
+typedef void (*bthost_cid_hook_func_t)(const void *data, uint16_t len,
+                                                       void *user_data);
+
+void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid,
+                               bthost_cid_hook_func_t func, void *user_data);
+
+void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid,
+                                       const void *data, uint16_t len);
+
 typedef void (*bthost_l2cap_rsp_cb) (uint8_t code, const void *data,
                                                uint16_t len, void *user_data);
 
index 268fed5..b248cbb 100644 (file)
@@ -1006,6 +1006,8 @@ static gboolean process_changes(gpointer user_data)
        if (data->removed != NULL)
                emit_interfaces_removed(data);
 
+       data->process_id = 0;
+
        return FALSE;
 }
 
@@ -1019,6 +1021,7 @@ static void generic_unregister(DBusConnection *connection, void *user_data)
 
        if (data->process_id > 0) {
                g_source_remove(data->process_id);
+               data->process_id = 0;
                process_changes(data);
        }
 
index 05fe2c3..5598ccf 100644 (file)
@@ -757,6 +757,42 @@ const char *bt_compidtostr(int compid)
                return "VSN Technologies Inc.";
        case 248:
                return "AceUni Corp., Ltd.";
+       case 249:
+               return "StickNFind";
+       case 250:
+               return "Crystal Code AB";
+       case 251:
+               return "KOUKAAM a.s.";
+       case 252:
+               return "Delphi Corporation";
+       case 253:
+               return "ValenceTech Limited";
+       case 254:
+               return "Reserved";
+       case 255:
+               return "Typo Products, LLC";
+       case 256:
+               return "TomTom International BV";
+       case 257:
+               return "Fugoo, Inc";
+       case 258:
+               return "Keiser Corporation";
+       case 259:
+               return "Bang & Olufsen A/S";
+       case 260:
+               return "PLUS Locations Systems Pty Ltd";
+       case 261:
+               return "Ubiquitous Computing Technology Corporation";
+       case 262:
+               return "Innovative Yachtter Solutions";
+       case 263:
+               return "William Demant Holding A/S";
+       case 264:
+               return "Chicony Electronics Co., Ltd.";
+       case 265:
+               return "Atus BV";
+       case 266:
+               return "Codegate Ltd.";
        case 65535:
                return "internal use";
        default:
index 2245ab3..2aec950 100644 (file)
@@ -706,6 +706,75 @@ struct bt_hci_cmd_write_voice_setting {
        uint16_t setting;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_AUTO_FLUSH_TIMEOUT     0x0c27
+struct bt_hci_cmd_read_auto_flush_timeout {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_auto_flush_timeout {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT    0x0c28
+struct bt_hci_cmd_write_auto_flush_timeout {
+       uint16_t handle;
+       uint16_t timeout;
+} __attribute__ ((packed));
+struct bt_hci_rsp_write_auto_flush_timeout {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_NUM_BROADCAST_RETRANS  0x0c29
+struct bt_hci_rsp_read_num_broadcast_retrans {
+       uint8_t  status;
+       uint8_t  num_retrans;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_NUM_BROADCAST_RETRANS 0x0c2a
+struct bt_hci_cmd_write_num_broadcast_retrans {
+       uint8_t  num_retrans;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_HOLD_MODE_ACTIVITY     0x0c2b
+struct bt_hci_rsp_read_hold_mode_activity {
+       uint8_t  status;
+       uint8_t  activity;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_HOLD_MODE_ACTIVITY    0x0c2c
+struct bt_hci_cmd_write_hold_mode_activity {
+       uint8_t  activity;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_TX_POWER               0x0c2d
+struct bt_hci_cmd_read_tx_power {
+       uint16_t handle;
+       uint8_t  type;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_tx_power {
+       uint8_t  status;
+       uint16_t handle;
+       int8_t   level;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_SYNC_FLOW_CONTROL      0x0c2e
+struct bt_hci_rsp_read_sync_flow_control {
+       uint8_t  status;
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_SYNC_FLOW_CONTROL     0x0c2f
+struct bt_hci_cmd_write_sync_flow_control {
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SET_HOST_FLOW_CONTROL       0x0c31
+struct bt_hci_cmd_set_host_flow_control {
+       uint8_t  enable;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_HOST_BUFFER_SIZE            0x0c33
 struct bt_hci_cmd_host_buffer_size {
        uint16_t acl_mtu;
@@ -877,6 +946,16 @@ struct bt_hci_cmd_enhanced_flush {
        uint8_t  type;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_SEND_KEYPRESS_NOTIFY                0x0c60
+struct bt_hci_cmd_send_keypress_notify {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+} __attribute__ ((packed));
+struct bt_hci_rsp_send_keypress_notify {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_SET_EVENT_MASK_PAGE2                0x0c63
 struct bt_hci_cmd_set_event_mask_page2 {
        uint8_t  mask[8];
@@ -1107,6 +1186,11 @@ struct bt_hci_rsp_write_remote_amp_assoc {
 
 #define BT_HCI_CMD_ENABLE_DUT_MODE             0x1803
 
+#define BT_HCI_CMD_WRITE_SSP_DEBUG_MODE                0x1804
+struct bt_hci_cmd_write_ssp_debug_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_LE_SET_EVENT_MASK           0x2001
 struct bt_hci_cmd_le_set_event_mask {
        uint8_t  mask[8];
index b8dce1f..af4171f 100644 (file)
@@ -58,10 +58,10 @@ int num_columns(void)
        if (__builtin_expect(!!(cached_num_columns < 0), 0)) {
                struct winsize ws;
 
-               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
-                       return -1;
-
-               if (ws.ws_col > 0)
+               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 ||
+                                                               ws.ws_col == 0)
+                       cached_num_columns = FALLBACK_TERMINAL_WIDTH;
+               else
                        cached_num_columns = ws.ws_col;
        }
 
index 6139cc2..885eb34 100644 (file)
@@ -40,6 +40,8 @@ bool use_color(void);
 
 #define COLOR_ERROR    "\x1B[1;31m"
 
+#define FALLBACK_TERMINAL_WIDTH 80
+
 #define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
 do { \
        printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
index e72b240..aed9b03 100644 (file)
@@ -70,6 +70,7 @@ static const struct option main_options[] = {
        { "time",    no_argument,       NULL, 't' },
        { "date",    no_argument,       NULL, 'T' },
        { "sco",     no_argument,       NULL, 'S' },
+       { "todo",    no_argument,       NULL, '#' },
        { "version", no_argument,       NULL, 'v' },
        { "help",    no_argument,       NULL, 'h' },
        { }
@@ -126,6 +127,9 @@ int main(int argc, char *argv[])
                case 'S':
                        filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
                        break;
+               case '#':
+                       packet_todo();
+                       return EXIT_SUCCESS;
                case 'v':
                        printf("%s\n", VERSION);
                        return EXIT_SUCCESS;
index 55c9f0f..0efa60b 100644 (file)
@@ -599,7 +599,7 @@ static const struct {
        const char *str;
 } major_class_av_table[] = {
        { 0x00, "Uncategorized, code for device not assigned"   },
-       { 0x01, "earable Headset Device"                        },
+       { 0x01, "Wearable Headset Device"                       },
        { 0x02, "Hands-free Device"                             },
        { 0x04, "Microphone"                                    },
        { 0x05, "Loudspeaker"                                   },
@@ -740,6 +740,96 @@ static void print_dev_class(const uint8_t *dev_class)
                                "  Unknown service class (0x%2.2x)", mask);
 }
 
+static void print_num_broadcast_retrans(uint8_t num_retrans)
+{
+       print_field("Number of broadcast retransmissions: %u", num_retrans);
+}
+
+static void print_hold_mode_activity(uint8_t activity)
+{
+       print_field("Activity: 0x%2.2x", activity);
+
+       if (activity == 0x00) {
+               print_field("  Maintain current Power State");
+               return;
+       }
+
+       if (activity & 0x01)
+               print_field("  Suspend Page Scan");
+       if (activity & 0x02)
+               print_field("  Suspend Inquiry Scan");
+       if (activity & 0x04)
+               print_field("  Suspend Periodic Inquiries");
+}
+
+static void print_power_type(uint8_t type)
+{
+       const char *str;
+
+       switch (type) {
+       case 0x00:
+               str = "Current Transmit Power Level";
+               break;
+       case 0x01:
+               str = "Maximum Transmit Power Level";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, type);
+}
+
+static void print_power_level(int8_t level)
+{
+       print_field("TX power: %d dBm", level);
+}
+
+static void print_sync_flow_control(uint8_t enable)
+{
+       const char *str;
+
+       switch (enable) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Flow control: %s (0x%2.2x)", str, enable);
+}
+
+static void print_host_flow_control(uint8_t enable)
+{
+       const char *str;
+
+       switch (enable) {
+       case 0x00:
+               str = "Off";
+               break;
+       case 0x01:
+               str = "ACL Data Packets";
+               break;
+       case 0x02:
+               str = "Synchronous Data Packets";
+               break;
+       case 0x03:
+               str = "ACL and Synchronous Data Packets";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Flow control: %s (0x%2.2x)", str, enable);
+}
+
 static void print_voice_setting(uint16_t setting)
 {
        print_field("Setting: 0x%4.4x", btohs(setting));
@@ -797,7 +887,23 @@ static void print_scan_enable(uint8_t scan_enable)
 
 static void print_link_policy(uint16_t link_policy)
 {
-       print_field("Link policy: 0x%4.4x", btohs(link_policy));
+       uint16_t policy = btohs(link_policy);
+
+       print_field("Link policy: 0x%4.4x", policy);
+
+       if (policy == 0x0000) {
+               print_field("  Disable All Modes");
+               return;
+       }
+
+       if (policy & 0x0001)
+               print_field("  Enable Role Switch");
+       if (policy & 0x0002)
+               print_field("  Enable Hold Mode");
+       if (policy & 0x0004)
+               print_field("  Enable Sniff Mode");
+       if (policy & 0x0008)
+               print_field("  Enabled Park State");
 }
 
 static void print_air_mode(uint8_t mode)
@@ -924,6 +1030,25 @@ static void print_simple_pairing_mode(uint8_t mode)
        print_field("Mode: %s (0x%2.2x)", str, mode);
 }
 
+static void print_ssp_debug_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Debug mode: %s (0x%2.2x)", str, mode);
+}
+
 static void print_pscan_rep_mode(uint8_t pscan_rep_mode)
 {
        const char *str;
@@ -1589,6 +1714,14 @@ static void print_channel_map(const uint8_t *map)
        print_field("Channel map: 0x%s", str);
 }
 
+static void print_flush_timeout(uint16_t timeout)
+{
+       if (timeout)
+               print_timeout(timeout);
+       else
+               print_field("Timeout: No Automatic Flush");
+}
+
 void packet_print_version(const char *label, uint8_t version,
                                const char *sublabel, uint16_t subversion)
 {
@@ -2180,7 +2313,7 @@ static void print_manufacturer_apple(const void *data, uint8_t data_len)
                break;
        case 0x02:
                len = *((uint8_t *) (data + 1));
-               if (len != 0x15) {
+               if (len != 0x15 || len != data_len - 2) {
                        print_hex_field("  Data", data, data_len);
                        break;
                }
@@ -2221,6 +2354,39 @@ static void print_manufacturer_data(const void *data, uint8_t data_len)
        }
 }
 
+static void print_device_id(const void *data, uint8_t data_len)
+{
+       uint16_t source;
+       const char *str;
+
+       if (data_len < 8)
+               return;
+
+       source = bt_get_le16(data);
+
+       switch (source) {
+       case 0x0001:
+               str = "Bluetooth SIG assigned";
+               break;
+       case 0x0002:
+               str = "USB Implementer's Forum assigned";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Device ID: %s (0x%4.4x)", str, source);
+
+       if (source == 0x0001)
+               packet_print_company("  Vendor", bt_get_le16(data + 2));
+       else
+               print_field("  Vendor: 0x%4.4x", bt_get_le16(data + 2));
+
+       print_field("  Product: 0x%4.4x", bt_get_le16(data + 4));
+       print_field("  Version: 0x%4.4x", bt_get_le16(data + 6));
+}
+
 static void print_uuid16_list(const char *label, const void *data,
                                                        uint8_t data_len)
 {
@@ -2422,15 +2588,7 @@ static void print_eir(const uint8_t *eir, uint8_t eir_len, bool le)
                        if (le)
                                print_hex_field("SMP TK", data, data_len);
                        else if (data_len >= 8)
-                               print_field("Device ID: "
-                                               "Source 0x%4.4x "
-                                               "Vendor 0x%4.4x "
-                                               "Product 0x%4.4x "
-                                               "Version 0x%4.4x",
-                                               bt_get_le16(&data[0]),
-                                               bt_get_le16(&data[2]),
-                                               bt_get_le16(&data[4]),
-                                               bt_get_le16(&data[6]));
+                               print_device_id(data, data_len);
                        break;
 
                case BT_EIR_SMP_OOB_FLAGS:
@@ -3601,6 +3759,107 @@ static void write_voice_setting_cmd(const void *data, uint8_t size)
        print_voice_setting(cmd->setting);
 }
 
+static void read_auto_flush_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_auto_flush_timeout *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_auto_flush_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_auto_flush_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_flush_timeout(rsp->timeout);
+}
+
+static void write_auto_flush_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_auto_flush_timeout *cmd = data;
+
+       print_handle(cmd->handle);
+       print_flush_timeout(cmd->timeout);
+}
+
+static void write_auto_flush_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_write_auto_flush_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void read_num_broadcast_retrans_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_num_broadcast_retrans *rsp = data;
+
+       print_status(rsp->status);
+       print_num_broadcast_retrans(rsp->num_retrans);
+}
+
+static void write_num_broadcast_retrans_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_num_broadcast_retrans *cmd = data;
+
+       print_num_broadcast_retrans(cmd->num_retrans);
+}
+
+static void read_hold_mode_activity_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_hold_mode_activity *rsp = data;
+
+       print_status(rsp->status);
+       print_hold_mode_activity(rsp->activity);
+}
+
+static void write_hold_mode_activity_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_hold_mode_activity *cmd = data;
+
+       print_hold_mode_activity(cmd->activity);
+}
+
+static void read_tx_power_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_tx_power *cmd = data;
+
+       print_handle(cmd->handle);
+       print_power_type(cmd->type);
+}
+
+static void read_tx_power_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_tx_power *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_power_level(rsp->level);
+}
+
+static void read_sync_flow_control_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_sync_flow_control *rsp = data;
+
+       print_status(rsp->status);
+       print_sync_flow_control(rsp->enable);
+}
+
+static void write_sync_flow_control_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_sync_flow_control *cmd = data;
+
+       print_sync_flow_control(cmd->enable);
+}
+
+static void set_host_flow_control_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_host_flow_control *cmd = data;
+
+       print_host_flow_control(cmd->enable);
+}
+
 static void host_buffer_size_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_host_buffer_size *cmd = data;
@@ -3824,14 +4083,14 @@ static void read_inquiry_resp_tx_power_rsp(const void *data, uint8_t size)
        const struct bt_hci_rsp_read_inquiry_resp_tx_power *rsp = data;
 
        print_status(rsp->status);
-       print_field("TX power: %d dBm", rsp->level);
+       print_power_level(rsp->level);
 }
 
 static void write_inquiry_tx_power_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_write_inquiry_tx_power *cmd = data;
 
-       print_field("TX power: %d dBm", cmd->level);
+       print_power_level(cmd->level);
 }
 
 static void enhanced_flush_cmd(const void *data, uint8_t size)
@@ -3853,6 +4112,45 @@ static void enhanced_flush_cmd(const void *data, uint8_t size)
        print_field("Type: %s (0x%2.2x)", str, cmd->type);
 }
 
+static void send_keypress_notify_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_send_keypress_notify *cmd = data;
+       const char *str;
+
+       print_bdaddr(cmd->bdaddr);
+
+       switch (cmd->type) {
+       case 0x00:
+               str = "Passkey entry started";
+               break;
+       case 0x01:
+               str = "Passkey digit entered";
+               break;
+       case 0x02:
+               str = "Passkey digit erased";
+               break;
+       case 0x03:
+               str = "Passkey cleared";
+               break;
+       case 0x04:
+               str = "Passkey entry completed";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, cmd->type);
+}
+
+static void send_keypress_notify_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_send_keypress_notify *rsp = data;
+
+       print_status(rsp->status);
+       print_bdaddr(rsp->bdaddr);
+}
+
 static void set_event_mask_page2_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_set_event_mask_page2 *cmd = data;
@@ -4226,6 +4524,13 @@ static void write_remote_amp_assoc_rsp(const void *data, uint8_t size)
        print_phy_handle(rsp->phy_handle);
 }
 
+static void write_ssp_debug_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_ssp_debug_mode *cmd = data;
+
+       print_ssp_debug_mode(cmd->mode);
+}
+
 static void le_set_event_mask_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_le_set_event_mask *cmd = data;
@@ -4334,6 +4639,7 @@ static void le_set_adv_parameters_cmd(const void *data, uint8_t size)
        case 0x03:
                str = "Allow Scan Request from White List Only, "
                        "Allow Connect Request from White List Only";
+               break;
        default:
                str = "Reserved";
                break;
@@ -4347,7 +4653,7 @@ static void le_read_adv_tx_power_rsp(const void *data, uint8_t size)
        const struct bt_hci_rsp_le_read_adv_tx_power *rsp = data;
 
        print_status(rsp->status);
-       print_field("TX power: %d dBm", rsp->level);
+       print_power_level(rsp->level);
 }
 
 static void le_set_adv_data_cmd(const void *data, uint8_t size)
@@ -4922,16 +5228,36 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c26,  75, "Write Voice Setting",
                                write_voice_setting_cmd, 2, true,
                                status_rsp, 1, true },
-       { 0x0c27,  76, "Read Automatic Flush Timeout" },
-       { 0x0c28,  77, "Write Automatic Flush Timeout" },
-       { 0x0c29,  78, "Read Num Broadcast Retransmissions" },
-       { 0x0c2a,  79, "Write Num Broadcast Retransmissions" },
-       { 0x0c2b,  80, "Read Hold Mode Activity" },
-       { 0x0c2c,  81, "Write Hold Mode Activity" },
-       { 0x0c2d,  82, "Read Transmit Power Level" },
-       { 0x0c2e,  83, "Read Sync Flow Control Enable" },
-       { 0x0c2f,  84, "Write Sync Flow Control Enable" },
-       { 0x0c31,  85, "Set Host Controller To Host Flow" },
+       { 0x0c27,  76, "Read Automatic Flush Timeout",
+                               read_auto_flush_timeout_cmd, 2, true,
+                               read_auto_flush_timeout_rsp, 5, true },
+       { 0x0c28,  77, "Write Automatic Flush Timeout",
+                               write_auto_flush_timeout_cmd, 4, true,
+                               write_auto_flush_timeout_rsp, 3, true },
+       { 0x0c29,  78, "Read Num Broadcast Retransmissions",
+                               null_cmd, 0, true,
+                               read_num_broadcast_retrans_rsp, 2, true },
+       { 0x0c2a,  79, "Write Num Broadcast Retransmissions",
+                               write_num_broadcast_retrans_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c2b,  80, "Read Hold Mode Activity",
+                               null_cmd, 0, true,
+                               read_hold_mode_activity_rsp, 2, true },
+       { 0x0c2c,  81, "Write Hold Mode Activity",
+                               write_hold_mode_activity_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c2d,  82, "Read Transmit Power Level",
+                               read_tx_power_cmd, 3, true,
+                               read_tx_power_rsp, 4, true },
+       { 0x0c2e,  83, "Read Sync Flow Control Enable",
+                               null_cmd, 0, true,
+                               read_sync_flow_control_rsp, 2, true },
+       { 0x0c2f,  84, "Write Sync Flow Control Enable",
+                               write_sync_flow_control_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c31,  85, "Set Controller To Host Flow Control",
+                               set_host_flow_control_cmd, 1, true,
+                               status_rsp, 1, true },
        { 0x0c33,  86, "Host Buffer Size",
                                host_buffer_size_cmd, 7, true,
                                status_rsp, 1, true },
@@ -5017,7 +5343,9 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c5b, 147, "Write Default Erroneous Reporting" },
        { 0x0c5f, 158, "Enhanced Flush",
                                enhanced_flush_cmd, 3, true },
-       { 0x0c60, 162, "Send Keypress Notification" },
+       { 0x0c60, 162, "Send Keypress Notification",
+                               send_keypress_notify_cmd, 7, true,
+                               send_keypress_notify_rsp, 7, true },
        { 0x0c61, 176, "Read Logical Link Accept Timeout" },
        { 0x0c62, 177, "Write Logical Link Accept Timeout" },
        { 0x0c63, 178, "Set Event Mask Page 2",
@@ -5126,7 +5454,9 @@ static const struct opcode_data opcode_table[] = {
        { 0x1803, 130, "Enable Device Under Test Mode",
                                null_cmd, 0, true,
                                status_rsp, 1, true },
-       { 0x1804, 157, "Write Simple Pairing Debug Mode" },
+       { 0x1804, 157, "Write Simple Pairing Debug Mode",
+                               write_ssp_debug_mode_cmd, 1, true,
+                               status_rsp, 1, true },
        { 0x1807, 189, "Enable AMP Receiver Reports" },
        { 0x1808, 190, "AMP Test End" },
        { 0x1809, 191, "AMP Test" },
@@ -6472,3 +6802,36 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
        if (filter_mask & PACKET_FILTER_SHOW_SCO_DATA)
                packet_hexdump(data, size);
 }
+
+void packet_todo(void)
+{
+       int i;
+
+       printf("HCI commands with missing decodings:\n");
+
+       for (i = 0; opcode_table[i].str; i++) {
+               if (opcode_table[i].bit < 0)
+                       continue;
+
+               if (opcode_table[i].cmd_func)
+                       continue;
+
+               printf("\t%s\n", opcode_table[i].str);
+       }
+
+       printf("HCI events with missing decodings:\n");
+
+       for (i = 0; event_table[i].str; i++) {
+               if (event_table[i].func)
+                       continue;
+
+               printf("\t%s\n", event_table[i].str);
+       }
+
+       for (i = 0; subevent_table[i].str; i++) {
+               if (subevent_table[i].func)
+                       continue;
+
+               printf("\t%s\n", subevent_table[i].str);
+       }
+}
index 07c1ec3..d44849c 100644 (file)
@@ -67,3 +67,5 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
                                        const void *data, uint16_t size);
 void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
                                        const void *data, uint16_t size);
+
+void packet_todo(void);
index 61a06b2..80645f8 100644 (file)
@@ -50,8 +50,6 @@
 #include "obexd.h"
 #include "server.h"
 
-#define DEFAULT_ROOT_PATH "/tmp"
-
 #define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
 
 static GMainLoop *main_loop = NULL;
@@ -167,7 +165,7 @@ static GOptionEntry options[] = {
                                "Specify root folder location. Both absolute "
                                "and relative can be used, but relative paths "
                                "are assumed to be relative to user $HOME "
-                               "folder", "PATH" },
+                               "folder. Default $XDG_CACHE_HOME", "PATH" },
        { "root-setup", 'S', 0, G_OPTION_ARG_STRING, &option_root_setup,
                                "Root folder setup script", "SCRIPT" },
        { "symlinks", 'l', 0, G_OPTION_ARG_NONE, &option_symlinks,
@@ -285,8 +283,11 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
-       if (option_root == NULL)
-               option_root = g_strdup(DEFAULT_ROOT_PATH);
+       if (option_root == NULL) {
+               option_root = g_build_filename(g_get_user_cache_dir(), "obexd",
+                                                                       NULL);
+               g_mkdir_with_parents(option_root, 0700);
+       }
 
        if (option_root[0] != '/') {
                char *old_root = option_root, *home = getenv("HOME");
index beda307..6cc21ee 100644 (file)
  */
 
 static uint16_t wii_ids[][2] = {
-       { 0x057e, 0x0306 },
-       { 0x057e, 0x0330 },
+       { 0x057e, 0x0306 },             /* 1st gen */
+       { 0x054c, 0x0306 },             /* LEGO wiimote */
+       { 0x057e, 0x0330 },             /* 2nd gen */
 };
 
 static const char *wii_names[] = {
-       "Nintendo RVL-CNT-01",
-       "Nintendo RVL-CNT-01-TR",
-       "Nintendo RVL-WBC-01",
+       "Nintendo RVL-CNT-01",          /* 1st gen */
+       "Nintendo RVL-CNT-01-TR",       /* 2nd gen */
+       "Nintendo RVL-CNT-01-UC",       /* Wii U Pro Controller */
+       "Nintendo RVL-WBC-01",          /* Balance Board */
 };
 
 static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
index 8477b5d..864cb18 100644 (file)
@@ -1187,17 +1187,8 @@ static struct a2dp_server *find_server(GSList *list, struct btd_adapter *a)
 static struct a2dp_server *a2dp_server_register(struct btd_adapter *adapter)
 {
        struct a2dp_server *server;
-       int av_err;
 
        server = g_new0(struct a2dp_server, 1);
-
-       av_err = avdtp_init(adapter);
-       if (av_err < 0) {
-               DBG("AVDTP not registered");
-               g_free(server);
-               return NULL;
-       }
-
        server->adapter = btd_adapter_ref(adapter);
        servers = g_slist_append(servers, server);
 
@@ -1217,8 +1208,6 @@ static void a2dp_unregister_sep(struct a2dp_sep *sep)
 
 static void a2dp_server_unregister(struct a2dp_server *server)
 {
-       avdtp_exit(server->adapter);
-
        servers = g_slist_remove(servers, server);
        btd_adapter_unref(server->adapter);
        g_free(server);
@@ -1872,10 +1861,22 @@ static void a2dp_sink_remove(struct btd_service *service)
 static int a2dp_source_connect(struct btd_service *service)
 {
        struct btd_device *dev = btd_service_get_device(service);
+       struct btd_adapter *adapter = device_get_adapter(dev);
+       struct a2dp_server *server;
        const char *path = device_get_path(dev);
 
        DBG("path %s", path);
 
+       server = find_server(servers, adapter);
+       if (!server || !server->sink_enabled) {
+               DBG("Unexpected error: cannot find server");
+               return -EPROTONOSUPPORT;
+       }
+
+       /* Return protocol not available if no record/endpoint exists */
+       if (server->sink_record_id == 0)
+               return -ENOPROTOOPT;
+
        return source_connect(service);
 }
 
@@ -1892,10 +1893,22 @@ static int a2dp_source_disconnect(struct btd_service *service)
 static int a2dp_sink_connect(struct btd_service *service)
 {
        struct btd_device *dev = btd_service_get_device(service);
+       struct btd_adapter *adapter = device_get_adapter(dev);
+       struct a2dp_server *server;
        const char *path = device_get_path(dev);
 
        DBG("path %s", path);
 
+       server = find_server(servers, adapter);
+       if (!server || !server->source_enabled) {
+               DBG("Unexpected error: cannot find server");
+               return -EPROTONOSUPPORT;
+       }
+
+       /* Return protocol not available if no record/endpoint exists */
+       if (server->source_record_id == 0)
+               return -ENOPROTOOPT;
+
        return sink_connect(service);
 }
 
index dab8f1c..9378350 100644 (file)
@@ -3683,6 +3683,45 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        &req, sizeof(req));
 }
 
+static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
+{
+       GError *err = NULL;
+       GIOChannel *io;
+
+       io = bt_io_listen(NULL, avdtp_confirm_cb,
+                               NULL, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_PSM, AVDTP_PSM,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_MASTER, master,
+                               BT_IO_OPT_INVALID);
+       if (!io) {
+               error("%s", err->message);
+               g_error_free(err);
+       }
+
+       return io;
+}
+
+static struct avdtp_server *avdtp_server_init(struct btd_adapter *adapter)
+{
+       struct avdtp_server *server;
+
+       server = g_new0(struct avdtp_server, 1);
+
+       server->io = avdtp_server_socket(adapter_get_address(adapter), TRUE);
+       if (!server->io) {
+               g_free(server);
+               return NULL;
+       }
+
+       server->adapter = btd_adapter_ref(adapter);
+
+       servers = g_slist_append(servers, server);
+
+       return server;
+}
+
 struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
                                                uint8_t type,
                                                uint8_t media_type,
@@ -3696,8 +3735,11 @@ struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
        struct avdtp_local_sep *sep;
 
        server = find_server(servers, adapter);
-       if (!server)
-               return NULL;
+       if (!server) {
+               server = avdtp_server_init(adapter);
+               if (!server)
+                       return NULL;
+       }
 
        if (g_slist_length(server->seps) > MAX_SEID)
                return NULL;
@@ -3722,6 +3764,18 @@ struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
        return sep;
 }
 
+static void avdtp_server_destroy(struct avdtp_server *server)
+{
+       g_slist_free_full(server->sessions, avdtp_free);
+
+       servers = g_slist_remove(servers, server);
+
+       g_io_channel_shutdown(server->io, TRUE, NULL);
+       g_io_channel_unref(server->io);
+       btd_adapter_unref(server->adapter);
+       g_free(server);
+}
+
 int avdtp_unregister_sep(struct avdtp_local_sep *sep)
 {
        struct avdtp_server *server;
@@ -3740,27 +3794,12 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep)
 
        g_free(sep);
 
-       return 0;
-}
-
-static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
-{
-       GError *err = NULL;
-       GIOChannel *io;
+       if (server->seps)
+               return 0;
 
-       io = bt_io_listen(NULL, avdtp_confirm_cb,
-                               NULL, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, src,
-                               BT_IO_OPT_PSM, AVDTP_PSM,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               g_error_free(err);
-       }
+       avdtp_server_destroy(server);
 
-       return io;
+       return 0;
 }
 
 const char *avdtp_strerror(struct avdtp_error *err)
@@ -3823,43 +3862,6 @@ struct btd_device *avdtp_get_device(struct avdtp *session)
        return session->device;
 }
 
-int avdtp_init(struct btd_adapter *adapter)
-{
-       struct avdtp_server *server;
-
-       server = g_new0(struct avdtp_server, 1);
-
-       server->io = avdtp_server_socket(adapter_get_address(adapter), TRUE);
-       if (!server->io) {
-               g_free(server);
-               return -1;
-       }
-
-       server->adapter = btd_adapter_ref(adapter);
-
-       servers = g_slist_append(servers, server);
-
-       return 0;
-}
-
-void avdtp_exit(struct btd_adapter *adapter)
-{
-       struct avdtp_server *server;
-
-       server = find_server(servers, adapter);
-       if (!server)
-               return;
-
-       g_slist_free_full(server->sessions, avdtp_free);
-
-       servers = g_slist_remove(servers, server);
-
-       g_io_channel_shutdown(server->io, TRUE, NULL);
-       g_io_channel_unref(server->io);
-       btd_adapter_unref(server->adapter);
-       g_free(server);
-}
-
 gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
 {
        return g_slist_find(session->streams, stream) ? TRUE : FALSE;
index 3bf7503..5606506 100644 (file)
@@ -308,6 +308,3 @@ struct btd_adapter *avdtp_get_adapter(struct avdtp *session);
 struct btd_device *avdtp_get_device(struct avdtp *session);
 
 void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc);
-
-int avdtp_init(struct btd_adapter *adapter);
-void avdtp_exit(struct btd_adapter *adapter);
index 296067c..cd027c6 100644 (file)
@@ -3363,9 +3363,6 @@ static void target_init(struct avrcp *session)
        if (service != NULL)
                btd_service_connecting_complete(service, 0);
 
-       if (target->version < 0x0103)
-               return;
-
        player = g_slist_nth_data(server->players, 0);
        if (player != NULL) {
                target->player = player;
index 40a9c4e..d904a56 100644 (file)
@@ -99,7 +99,6 @@ static GSList *adapters = NULL;
 
 static struct mgmt *mgmt_master = NULL;
 
-#define MGMT_VERSION(v, r) ((v << 16) + (r))
 static uint8_t mgmt_version = 0;
 static uint8_t mgmt_revision = 0;
 
@@ -285,7 +284,7 @@ static void set_dev_class_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -487,7 +486,7 @@ static void set_mode_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -631,7 +630,7 @@ static void set_local_name_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -753,7 +752,7 @@ static void add_uuid_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -805,7 +804,7 @@ static void remove_uuid_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -856,7 +855,7 @@ static void clear_uuids_complete(uint8_t status, uint16_t length,
        }
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
@@ -1868,7 +1867,7 @@ static void property_set_mode_complete(uint8_t status, uint16_t length,
        g_dbus_pending_property_success(data->id);
 
        /*
-        * The parameters are idential and also the task that is
+        * The parameters are identical and also the task that is
         * required in both cases. So it is safe to just call the
         * event handling functions here.
         */
index 5d124e7..80c5f77 100644 (file)
@@ -82,7 +82,6 @@ void adapter_shutdown(void);
 
 struct btd_adapter *adapter_find(const bdaddr_t *sba);
 struct btd_adapter *adapter_find_by_id(int id);
-struct btd_adapter *adapter_get_default(void);
 void adapter_foreach(adapter_cb func, gpointer user_data);
 
 bool btd_adapter_get_pairable(struct btd_adapter *adapter);
index 2b73254..35e9457 100644 (file)
@@ -9,7 +9,7 @@ ExecStart=@libexecdir@/bluetoothd
 NotifyAccess=main
 #WatchdogSec=10
 #Restart=on-failure
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
+CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
 LimitNPROC=1
 
 [Install]
index 457ab64..82b66e6 100644 (file)
@@ -31,8 +31,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdbool.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
 #include <errno.h>
 #include <dirent.h>
 #include <time.h>
@@ -64,7 +62,6 @@
 #include "sdp-client.h"
 #include "attrib/gatt.h"
 #include "agent.h"
-#include "sdp-xml.h"
 #include "storage.h"
 #include "attrib-server.h"
 
@@ -148,7 +145,7 @@ typedef void (*attio_error_cb) (const GError *gerr, gpointer user_data);
 typedef void (*attio_success_cb) (gpointer user_data);
 
 struct att_callbacks {
-       attio_error_cb error;           /* Callback for error */
+       attio_error_cb err;             /* Callback for error */
        attio_success_cb success;       /* Callback for success */
        gpointer user_data;
 };
@@ -1159,8 +1156,15 @@ static void device_profile_connected(struct btd_device *dev,
        if (dev->pending == NULL)
                return;
 
-       if (!dev->connected && err == -EHOSTDOWN)
-               goto done;
+       if (!dev->connected) {
+               switch (-err) {
+               case EHOSTDOWN: /* page timeout */
+               case EHOSTUNREACH: /* adapter not powered */
+               case ECONNABORTED: /* adapter powered down */
+                       goto done;
+               }
+       }
+
 
        pending = dev->pending->data;
        l = find_service_with_profile(dev->pending, profile);
@@ -1300,6 +1304,9 @@ static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg,
        if (dev->pending || dev->connect || dev->browse)
                return btd_error_in_progress(msg);
 
+       if (!btd_adapter_get_powered(dev->adapter))
+               return btd_error_not_ready(msg);
+
        device_set_temporary(dev, FALSE);
 
        if (!dev->svc_resolved)
@@ -3243,8 +3250,8 @@ static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
        if (gerr) {
                DBG("%s", gerr->message);
 
-               if (attcb->error)
-                       attcb->error(gerr, user_data);
+               if (attcb->err)
+                       attcb->err(gerr, user_data);
 
                err = -ECONNABORTED;
                goto done;
@@ -3348,7 +3355,7 @@ int device_connect_le(struct btd_device *dev)
        DBG("Connection attempt to: %s", addr);
 
        attcb = g_new0(struct att_callbacks, 1);
-       attcb->error = att_error_cb;
+       attcb->err = att_error_cb;
        attcb->success = att_success_cb;
        attcb->user_data = dev;
 
@@ -3438,7 +3445,7 @@ static int device_browse_primary(struct btd_device *device, DBusMessage *msg)
        }
 
        attcb = g_new0(struct att_callbacks, 1);
-       attcb->error = att_browse_error_cb;
+       attcb->err = att_browse_error_cb;
        attcb->success = att_browse_cb;
        attcb->user_data = device;
 
@@ -3446,6 +3453,7 @@ static int device_browse_primary(struct btd_device *device, DBusMessage *msg)
                                attcb, NULL, NULL,
                                BT_IO_OPT_SOURCE_BDADDR,
                                adapter_get_address(adapter),
+                               BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
                                BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
                                BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
                                BT_IO_OPT_CID, ATT_CID,
index 2789db6..51f3048 100644 (file)
@@ -196,30 +196,23 @@ static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct search_context *ctxt = user_data;
-       int err = 0;
 
        if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
-               err = EIO;
-               goto failed;
-       }
-
-       if (sdp_process(ctxt->session) < 0)
-               goto failed;
-
-       return TRUE;
-
-failed:
-       if (err) {
                sdp_close(ctxt->session);
                ctxt->session = NULL;
 
                if (ctxt->cb)
-                       ctxt->cb(NULL, err, ctxt->user_data);
+                       ctxt->cb(NULL, -EIO, ctxt->user_data);
 
                search_context_cleanup(ctxt);
+               return FALSE;
        }
 
-       return FALSE;
+       /* If sdp_process fails it calls search_completed_cb */
+       if (sdp_process(ctxt->session) < 0)
+               return FALSE;
+
+       return TRUE;
 }
 
 static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
index 52a8291..7a480d6 100644 (file)
@@ -198,18 +198,16 @@ int btd_service_connect(struct btd_service *service)
                return -EBUSY;
        }
 
-       change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);
-
        err = profile->connect(service);
-       if (err == 0)
+       if (err == 0) {
+               change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);
                return 0;
+       }
 
        ba2str(device_get_address(service->device), addr);
        error("%s profile connect failed for %s: %s", profile->name, addr,
                                                                strerror(-err));
 
-       btd_service_connecting_complete(service, err);
-
        return err;
 }
 
index 60a2128..e23cc7d 100644 (file)
@@ -24,6 +24,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#define MGMT_VERSION(v, r) (((v) << 16) + (r))
+
 typedef void (*mgmt_destroy_func_t)(void *user_data);
 
 struct mgmt;
index bb8a521..95b4abf 100644 (file)
@@ -221,18 +221,21 @@ static int usb_switch_dell(int fd, enum mode mode)
 static int find_device(struct udev_device *udev_dev)
 {
        char path[PATH_MAX];
-       const char *busnum, *devnum;
+       const char *busnum_str, *devnum_str;
+       int busnum, devnum;
        int fd;
 
-       busnum = udev_device_get_sysattr_value(udev_dev, "busnum");
-       if (!busnum)
+       busnum_str = udev_device_get_sysattr_value(udev_dev, "busnum");
+       if (!busnum_str)
                return -1;
+       busnum = strtol(busnum_str, NULL, 10);
 
-       devnum = udev_device_get_sysattr_value(udev_dev, "devnum");
-       if (!devnum)
+       devnum_str = udev_device_get_sysattr_value(udev_dev, "devnum");
+       if (!devnum_str)
                return -1;
+       devnum = strtol(devnum_str, NULL, 10);
 
-       snprintf(path, sizeof(path), "/dev/bus/usb/%s/%s", busnum, devnum);
+       snprintf(path, sizeof(path), "/dev/bus/usb/%03d/%03d", busnum, devnum);
 
        fd = open(path, O_RDWR, O_CLOEXEC);
        if (fd < 0) {
index df8f1bf..acfd7c3 100644 (file)
@@ -290,7 +290,8 @@ static const struct l2cap_server_data l2cap_server_nval_pdu_test1 = {
 };
 
 static const uint8_t l2cap_nval_dc_req[] = { 0x12, 0x34, 0x56, 0x78 };
-static const uint8_t l2cap_nval_cid_rsp[] = { 0x02, 0x00 };
+static const uint8_t l2cap_nval_cid_rsp[] = { 0x02, 0x00,
+                                               0x12, 0x34, 0x56, 0x78 };
 
 static const struct l2cap_server_data l2cap_server_nval_cid_test1 = {
        .send_req_code = BT_L2CAP_PDU_DISCONN_REQ,
@@ -302,7 +303,8 @@ static const struct l2cap_server_data l2cap_server_nval_cid_test1 = {
 };
 
 static const uint8_t l2cap_nval_cfg_req[] = { 0x12, 0x34, 0x00, 0x00 };
-static const uint8_t l2cap_nval_cfg_rsp[] = { 0x02, 0x00 };
+static const uint8_t l2cap_nval_cfg_rsp[] = { 0x02, 0x00,
+                                               0x12, 0x34, 0x00, 0x00 };
 
 static const struct l2cap_server_data l2cap_server_nval_cid_test2 = {
        .send_req_code = BT_L2CAP_PDU_CONFIG_REQ,
index 125532b..c5c8763 100644 (file)
@@ -280,6 +280,8 @@ static int do_connect(char *svr)
        addr.l2_family = AF_BLUETOOTH;
        bacpy(&addr.l2_bdaddr, &bdaddr);
        addr.l2_bdaddr_type = bdaddr_type;
+       if (cid)
+               addr.l2_cid = htobs(cid);
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                syslog(LOG_ERR, "Can't bind socket: %s (%d)",
index 2ef72cf..e2fe73d 100644 (file)
@@ -38,9 +38,8 @@
 #include "src/shared/mgmt.h"
 #include "src/shared/hciemu.h"
 
-static gboolean option_wait_powered = FALSE;
-
 struct test_data {
+       tester_data_func_t test_setup;
        const void *test_data;
        uint8_t expected_version;
        uint16_t expected_manufacturer;
@@ -299,6 +298,7 @@ static void test_condition_complete(struct test_data *data)
                if (!user) \
                        break; \
                user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+               user->test_setup = setup; \
                user->test_data = data; \
                user->expected_version = 0x06; \
                user->expected_manufacturer = 0x003f; \
@@ -306,7 +306,7 @@ static void test_condition_complete(struct test_data *data)
                user->initial_settings = 0x00000080; \
                user->unmet_conditions = 0; \
                tester_add_full(name, data, \
-                               test_pre_setup, setup, func, NULL, \
+                               test_pre_setup, test_setup, func, NULL, \
                                test_post_teardown, 2, user, free); \
        } while (0)
 
@@ -317,6 +317,7 @@ static void test_condition_complete(struct test_data *data)
                if (!user) \
                        break; \
                user->hciemu_type = HCIEMU_TYPE_BREDR; \
+               user->test_setup = setup; \
                user->test_data = data; \
                user->expected_version = 0x05; \
                user->expected_manufacturer = 0x003f; \
@@ -324,7 +325,7 @@ static void test_condition_complete(struct test_data *data)
                user->initial_settings = 0x00000080; \
                user->unmet_conditions = 0; \
                tester_add_full(name, data, \
-                               test_pre_setup, setup, func, NULL, \
+                               test_pre_setup, test_setup, func, NULL, \
                                test_post_teardown, 2, user, free); \
        } while (0)
 
@@ -335,6 +336,7 @@ static void test_condition_complete(struct test_data *data)
                if (!user) \
                        break; \
                user->hciemu_type = HCIEMU_TYPE_LE; \
+               user->test_setup = setup; \
                user->test_data = data; \
                user->expected_version = 0x06; \
                user->expected_manufacturer = 0x003f; \
@@ -342,7 +344,7 @@ static void test_condition_complete(struct test_data *data)
                user->initial_settings = 0x00000200; \
                user->unmet_conditions = 0; \
                tester_add_full(name, data, \
-                               test_pre_setup, setup, func, NULL, \
+                               test_pre_setup, test_setup, func, NULL, \
                                test_post_teardown, 2, user, free); \
        } while (0)
 
@@ -352,6 +354,9 @@ static void controller_setup(const void *test_data)
 }
 
 struct generic_data {
+       const uint16_t *setup_settings;
+       bool setup_nobredr;
+       bool setup_limited_discov;
        uint16_t setup_expect_hci_command;
        const void *setup_expect_hci_param;
        uint8_t setup_expect_hci_len;
@@ -480,11 +485,14 @@ static const struct generic_data set_powered_on_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static const uint16_t settings_powered[] = { MGMT_OP_SET_POWERED, 0 };
+
 static const char set_powered_off_param[] = { 0x00 };
 static const char set_powered_off_settings_param[] = { 0x80, 0x00, 0x00, 0x00 };
 static const char set_powered_off_class_of_dev[] = { 0x00, 0x00, 0x00 };
 
 static const struct generic_data set_powered_off_success_test = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_off_param,
        .send_len = sizeof(set_powered_off_param),
@@ -508,11 +516,13 @@ static const struct generic_data set_powered_off_class_test = {
 };
 
 static const struct generic_data set_powered_off_invalid_param_test_1 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_POWERED,
        .expect_status = MGMT_STATUS_INVALID_PARAMS,
 };
 
 static const struct generic_data set_powered_off_invalid_param_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_invalid_param,
        .send_len = sizeof(set_powered_invalid_param),
@@ -520,6 +530,7 @@ static const struct generic_data set_powered_off_invalid_param_test_2 = {
 };
 
 static const struct generic_data set_powered_off_invalid_param_test_3 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_garbage_param,
        .send_len = sizeof(set_powered_garbage_param),
@@ -544,6 +555,7 @@ static const struct generic_data set_connectable_on_success_test_1 = {
 };
 
 static const struct generic_data set_connectable_on_success_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_CONNECTABLE,
        .send_param = set_connectable_on_param,
        .send_len = sizeof(set_connectable_on_param),
@@ -583,12 +595,75 @@ static const struct generic_data set_connectable_on_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static uint16_t settings_powered_advertising[] = { MGMT_OP_SET_ADVERTISING,
+                                               MGMT_OP_SET_POWERED, 0 };
+
+static const char set_connectable_le_settings_param_1[] = { 0x02, 0x02, 0x00, 0x00 };
+static const char set_connectable_le_settings_param_2[] = { 0x03, 0x02, 0x00, 0x00 };
+static const char set_connectable_le_settings_param_3[] = { 0x03, 0x06, 0x00, 0x00 };
+
+static const struct generic_data set_connectable_on_le_test_1 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_le_settings_param_1,
+       .expect_len = sizeof(set_connectable_le_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_CONNECTABLE,
+};
+
+static const struct generic_data set_connectable_on_le_test_2 = {
+       .setup_settings = settings_powered,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_le_settings_param_2,
+       .expect_len = sizeof(set_connectable_le_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_CONNECTABLE,
+};
+
+static uint8_t set_connectable_on_adv_param[] = {
+               0x00, 0x08,                             /* min_interval */
+               0x00, 0x08,                             /* max_interval */
+               0x00,                                   /* type */
+               0x00,                                   /* own_addr_type */
+               0x00,                                   /* direct_addr_type */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* direct_addr */
+               0x07,                                   /* channel_map */
+               0x00,                                   /* filter_policy */
+};
+
+static const struct generic_data set_connectable_on_le_test_3 = {
+       .setup_settings = settings_powered_advertising,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_le_settings_param_3,
+       .expect_len = sizeof(set_connectable_le_settings_param_3),
+       .expect_settings_set = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_on_adv_param,
+       .expect_hci_len = sizeof(set_connectable_on_adv_param),
+};
+
+static const uint16_t settings_connectable[] = { MGMT_OP_SET_CONNECTABLE, 0 };
+static const uint16_t settings_powered_connectable[] = {
+                                               MGMT_OP_SET_CONNECTABLE,
+                                               MGMT_OP_SET_POWERED, 0 };
+static const uint16_t settings_powered_discoverable[] = {
+                                               MGMT_OP_SET_CONNECTABLE,
+                                               MGMT_OP_SET_DISCOVERABLE,
+                                               MGMT_OP_SET_POWERED, 0 };
+
 static const char set_connectable_off_param[] = { 0x00 };
 static const char set_connectable_off_settings_1[] = { 0x80, 0x00, 0x00, 0x00 };
 static const char set_connectable_off_settings_2[] = { 0x81, 0x00, 0x00, 0x00 };
 static const char set_connectable_off_scan_enable_param[] = { 0x00 };
 
 static const struct generic_data set_connectable_off_success_test_1 = {
+       .setup_settings = settings_connectable,
        .send_opcode = MGMT_OP_SET_CONNECTABLE,
        .send_param = set_connectable_off_param,
        .send_len = sizeof(set_connectable_off_param),
@@ -599,6 +674,21 @@ static const struct generic_data set_connectable_off_success_test_1 = {
 };
 
 static const struct generic_data set_connectable_off_success_test_2 = {
+       .setup_settings = settings_powered_connectable,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_settings_2,
+       .expect_len = sizeof(set_connectable_off_settings_2),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_connectable_off_scan_enable_param,
+       .expect_hci_len = sizeof(set_connectable_off_scan_enable_param),
+};
+
+static const struct generic_data set_connectable_off_success_test_3 = {
+       .setup_settings = settings_powered_discoverable,
        .send_opcode = MGMT_OP_SET_CONNECTABLE,
        .send_param = set_connectable_off_param,
        .send_len = sizeof(set_connectable_off_param),
@@ -611,10 +701,95 @@ static const struct generic_data set_connectable_off_success_test_2 = {
        .expect_hci_len = sizeof(set_connectable_off_scan_enable_param),
 };
 
+static const char set_connectable_off_le_settings_1[] = { 0x00, 0x02, 0x00, 0x00 };
+static const char set_connectable_off_le_settings_2[] = { 0x01, 0x06, 0x00, 0x00 };
+
+static uint16_t settings_le_connectable[] = { MGMT_OP_SET_LE,
+                                               MGMT_OP_SET_CONNECTABLE, 0 };
+
+static const struct generic_data set_connectable_off_le_test_1 = {
+       .setup_settings = settings_le_connectable,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_le_settings_1,
+       .expect_len = sizeof(set_connectable_off_le_settings_1),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+};
+
+static uint16_t settings_powered_le_connectable_advertising[] = {
+                                       MGMT_OP_SET_LE,
+                                       MGMT_OP_SET_CONNECTABLE,
+                                       MGMT_OP_SET_ADVERTISING,
+                                       MGMT_OP_SET_POWERED, 0 };
+
+static uint8_t set_connectable_off_adv_param[] = {
+               0x00, 0x08,                             /* min_interval */
+               0x00, 0x08,                             /* max_interval */
+               0x03,                                   /* type */
+               0x00,                                   /* own_addr_type */
+               0x00,                                   /* direct_addr_type */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* direct_addr */
+               0x07,                                   /* channel_map */
+               0x00,                                   /* filter_policy */
+};
+
+static const struct generic_data set_connectable_off_le_test_2 = {
+       .setup_settings = settings_powered_le_connectable_advertising,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_le_settings_2,
+       .expect_len = sizeof(set_connectable_off_le_settings_2),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_adv_param),
+};
+
+static uint16_t settings_powered_le_discoverable_advertising[] = {
+                                       MGMT_OP_SET_LE,
+                                       MGMT_OP_SET_CONNECTABLE,
+                                       MGMT_OP_SET_ADVERTISING,
+                                       MGMT_OP_SET_POWERED,
+                                       MGMT_OP_SET_DISCOVERABLE, 0 };
+
+static const struct generic_data set_connectable_off_le_test_3 = {
+       .setup_settings = settings_powered_le_discoverable_advertising,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_le_settings_2,
+       .expect_len = sizeof(set_connectable_off_le_settings_2),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_adv_param),
+};
+
+static const struct generic_data set_connectable_off_le_test_4 = {
+       .setup_settings = settings_powered_le_discoverable_advertising,
+       .setup_limited_discov = true,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_le_settings_2,
+       .expect_len = sizeof(set_connectable_off_le_settings_2),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_adv_param),
+};
+
 static const char set_fast_conn_on_param[] = { 0x01 };
 static const char set_fast_conn_on_settings_1[] = { 0x87, 0x00, 0x00, 0x00 };
 
 static const struct generic_data set_fast_conn_on_success_test_1 = {
+       .setup_settings = settings_powered_connectable,
        .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
        .send_param = set_fast_conn_on_param,
        .send_len = sizeof(set_fast_conn_on_param),
@@ -624,6 +799,14 @@ static const struct generic_data set_fast_conn_on_success_test_1 = {
        .expect_settings_set = MGMT_SETTING_FAST_CONNECTABLE,
 };
 
+static const struct generic_data set_fast_conn_on_not_supported_test_1 = {
+       .setup_settings = settings_powered_connectable,
+       .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
+       .send_param = set_fast_conn_on_param,
+       .send_len = sizeof(set_fast_conn_on_param),
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+};
+
 static const char set_pairable_on_param[] = { 0x01 };
 static const char set_pairable_invalid_param[] = { 0x02 };
 static const char set_pairable_garbage_param[] = { 0x01, 0x00 };
@@ -712,7 +895,16 @@ static const struct generic_data set_discoverable_on_not_powered_test_1 = {
        .expect_status = MGMT_STATUS_NOT_POWERED,
 };
 
+static const struct generic_data set_discoverable_on_not_powered_test_2 = {
+       .setup_settings = settings_connectable,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_timeout_param,
+       .send_len = sizeof(set_discoverable_timeout_param),
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+};
+
 static const struct generic_data set_discoverable_on_rejected_test_1 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_on_param,
        .send_len = sizeof(set_discoverable_on_param),
@@ -720,6 +912,7 @@ static const struct generic_data set_discoverable_on_rejected_test_1 = {
 };
 
 static const struct generic_data set_discoverable_on_rejected_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_on_param,
        .send_len = sizeof(set_discoverable_on_param),
@@ -727,6 +920,7 @@ static const struct generic_data set_discoverable_on_rejected_test_2 = {
 };
 
 static const struct generic_data set_discoverable_on_rejected_test_3 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_timeout_param,
        .send_len = sizeof(set_discoverable_timeout_param),
@@ -734,6 +928,7 @@ static const struct generic_data set_discoverable_on_rejected_test_3 = {
 };
 
 static const struct generic_data set_discoverable_on_success_test_1 = {
+       .setup_settings = settings_connectable,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_on_param,
        .send_len = sizeof(set_discoverable_on_param),
@@ -744,6 +939,7 @@ static const struct generic_data set_discoverable_on_success_test_1 = {
 };
 
 static const struct generic_data set_discoverable_on_success_test_2 = {
+       .setup_settings = settings_powered_connectable,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_on_param,
        .send_len = sizeof(set_discoverable_on_param),
@@ -756,7 +952,25 @@ static const struct generic_data set_discoverable_on_success_test_2 = {
        .expect_hci_len = sizeof(set_discoverable_on_scan_enable_param),
 };
 
+static uint8_t set_discov_on_le_param[] = { 0x0b, 0x06, 0x00, 0x00 };
+static uint8_t set_discov_adv_data[32] = { 0x06, 0x02, 0x01, 0x06,
+                                                               0x02, 0x0a, };
+
+static const struct generic_data set_discov_on_le_success_1 = {
+       .setup_settings = settings_powered_le_connectable_advertising,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_on_param,
+       .send_len = sizeof(set_discoverable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discov_on_le_param,
+       .expect_len = sizeof(set_discov_on_le_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_discov_adv_data,
+       .expect_hci_len = sizeof(set_discov_adv_data),
+};
+
 static const struct generic_data set_discoverable_off_success_test_1 = {
+       .setup_settings = settings_connectable,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_off_param,
        .send_len = sizeof(set_discoverable_off_param),
@@ -766,6 +980,7 @@ static const struct generic_data set_discoverable_off_success_test_1 = {
 };
 
 static const struct generic_data set_discoverable_off_success_test_2 = {
+       .setup_settings = settings_powered_discoverable,
        .send_opcode = MGMT_OP_SET_DISCOVERABLE,
        .send_param = set_discoverable_off_param,
        .send_len = sizeof(set_discoverable_off_param),
@@ -777,6 +992,69 @@ static const struct generic_data set_discoverable_off_success_test_2 = {
        .expect_hci_len = sizeof(set_discoverable_off_scan_enable_param),
 };
 
+static const uint8_t set_limited_discov_on_param[] = { 0x02, 0x01, 0x00 };
+
+static const struct generic_data set_limited_discov_on_success_1 = {
+       .setup_settings = settings_powered_connectable,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_limited_discov_on_param,
+       .send_len = sizeof(set_limited_discov_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_on_settings_param_2,
+       .expect_len = sizeof(set_discoverable_on_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_discoverable_on_scan_enable_param,
+       .expect_hci_len = sizeof(set_discoverable_on_scan_enable_param),
+};
+
+static uint8_t write_current_iac_lap_limited[] = { 0x01, 0x00, 0x8b, 0x9e };
+
+static const struct generic_data set_limited_discov_on_success_2 = {
+       .setup_settings = settings_powered_connectable,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_limited_discov_on_param,
+       .send_len = sizeof(set_limited_discov_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_on_settings_param_2,
+       .expect_len = sizeof(set_discoverable_on_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_WRITE_CURRENT_IAC_LAP,
+       .expect_hci_param = write_current_iac_lap_limited,
+       .expect_hci_len = sizeof(write_current_iac_lap_limited),
+};
+
+static uint8_t write_cod_limited[] = { 0x00, 0x20, 0x00 };
+
+static const struct generic_data set_limited_discov_on_success_3 = {
+       .setup_settings = settings_powered_connectable,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_limited_discov_on_param,
+       .send_len = sizeof(set_limited_discov_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_on_settings_param_2,
+       .expect_len = sizeof(set_discoverable_on_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_WRITE_CLASS_OF_DEV,
+       .expect_hci_param = write_cod_limited,
+       .expect_hci_len = sizeof(write_cod_limited),
+};
+
+static uint8_t set_limited_discov_adv_data[32] = { 0x06, 0x02, 0x01, 0x05,
+                                                               0x02, 0x0a, };
+
+static const struct generic_data set_limited_discov_on_le_success_1 = {
+       .setup_settings = settings_powered_le_connectable_advertising,
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_limited_discov_on_param,
+       .send_len = sizeof(set_limited_discov_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discov_on_le_param,
+       .expect_len = sizeof(set_discov_on_le_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_limited_discov_adv_data,
+       .expect_hci_len = sizeof(set_limited_discov_adv_data),
+};
+
+static uint16_t settings_link_sec[] = { MGMT_OP_SET_LINK_SECURITY, 0 };
+
 static const char set_link_sec_on_param[] = { 0x01 };
 static const char set_link_sec_invalid_param[] = { 0x02 };
 static const char set_link_sec_garbage_param[] = { 0x01, 0x00 };
@@ -795,6 +1073,7 @@ static const struct generic_data set_link_sec_on_success_test_1 = {
 };
 
 static const struct generic_data set_link_sec_on_success_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_LINK_SECURITY,
        .send_param = set_link_sec_on_param,
        .send_len = sizeof(set_link_sec_on_param),
@@ -808,6 +1087,7 @@ static const struct generic_data set_link_sec_on_success_test_2 = {
 };
 
 static const struct generic_data set_link_sec_on_success_test_3 = {
+       .setup_settings = settings_link_sec,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_on_param,
        .send_len = sizeof(set_powered_on_param),
@@ -847,12 +1127,17 @@ static const struct generic_data set_link_sec_on_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static const uint16_t settings_powered_link_sec[] = {
+                                               MGMT_OP_SET_LINK_SECURITY,
+                                               MGMT_OP_SET_POWERED, 0 };
+
 static const char set_link_sec_off_param[] = { 0x00 };
 static const char set_link_sec_off_settings_1[] = { 0x80, 0x00, 0x00, 0x00 };
 static const char set_link_sec_off_settings_2[] = { 0x81, 0x00, 0x00, 0x00 };
 static const char set_link_sec_off_auth_enable_param[] = { 0x00 };
 
 static const struct generic_data set_link_sec_off_success_test_1 = {
+       .setup_settings = settings_link_sec,
        .send_opcode = MGMT_OP_SET_LINK_SECURITY,
        .send_param = set_link_sec_off_param,
        .send_len = sizeof(set_link_sec_off_param),
@@ -863,6 +1148,7 @@ static const struct generic_data set_link_sec_off_success_test_1 = {
 };
 
 static const struct generic_data set_link_sec_off_success_test_2 = {
+       .setup_settings = settings_powered_link_sec,
        .send_opcode = MGMT_OP_SET_LINK_SECURITY,
        .send_param = set_link_sec_off_param,
        .send_len = sizeof(set_link_sec_off_param),
@@ -875,6 +1161,8 @@ static const struct generic_data set_link_sec_off_success_test_2 = {
        .expect_hci_len = sizeof(set_link_sec_off_auth_enable_param),
 };
 
+static uint16_t settings_ssp[] = { MGMT_OP_SET_SSP, 0 };
+
 static const char set_ssp_on_param[] = { 0x01 };
 static const char set_ssp_invalid_param[] = { 0x02 };
 static const char set_ssp_garbage_param[] = { 0x01, 0x00 };
@@ -893,6 +1181,7 @@ static const struct generic_data set_ssp_on_success_test_1 = {
 };
 
 static const struct generic_data set_ssp_on_success_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_SSP,
        .send_param = set_ssp_on_param,
        .send_len = sizeof(set_ssp_on_param),
@@ -906,6 +1195,7 @@ static const struct generic_data set_ssp_on_success_test_2 = {
 };
 
 static const struct generic_data set_ssp_on_success_test_3 = {
+       .setup_settings = settings_ssp,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_on_param,
        .send_len = sizeof(set_powered_on_param),
@@ -951,6 +1241,7 @@ static const char set_hs_garbage_param[] = { 0x01, 0x00 };
 static const char set_hs_settings_param_1[] = { 0xc0, 0x01, 0x00, 0x00 };
 
 static const struct generic_data set_hs_on_success_test = {
+       .setup_settings = settings_ssp,
        .send_opcode = MGMT_OP_SET_HS,
        .send_param = set_hs_on_param,
        .send_len = sizeof(set_hs_on_param),
@@ -961,11 +1252,13 @@ static const struct generic_data set_hs_on_success_test = {
 };
 
 static const struct generic_data set_hs_on_invalid_param_test_1 = {
+       .setup_settings = settings_ssp,
        .send_opcode = MGMT_OP_SET_HS,
        .expect_status = MGMT_STATUS_INVALID_PARAMS,
 };
 
 static const struct generic_data set_hs_on_invalid_param_test_2 = {
+       .setup_settings = settings_ssp,
        .send_opcode = MGMT_OP_SET_HS,
        .send_param = set_hs_invalid_param,
        .send_len = sizeof(set_hs_invalid_param),
@@ -973,6 +1266,7 @@ static const struct generic_data set_hs_on_invalid_param_test_2 = {
 };
 
 static const struct generic_data set_hs_on_invalid_param_test_3 = {
+       .setup_settings = settings_ssp,
        .send_opcode = MGMT_OP_SET_HS,
        .send_param = set_hs_garbage_param,
        .send_len = sizeof(set_hs_garbage_param),
@@ -980,6 +1274,7 @@ static const struct generic_data set_hs_on_invalid_param_test_3 = {
 };
 
 static const struct generic_data set_hs_on_invalid_index_test = {
+       .setup_settings = settings_ssp,
        .send_index_none = true,
        .send_opcode = MGMT_OP_SET_HS,
        .send_param = set_hs_on_param,
@@ -987,6 +1282,8 @@ static const struct generic_data set_hs_on_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static uint16_t settings_le[] = { MGMT_OP_SET_LE, 0 };
+
 static const char set_le_on_param[] = { 0x01 };
 static const char set_le_invalid_param[] = { 0x02 };
 static const char set_le_garbage_param[] = { 0x01, 0x00 };
@@ -1005,6 +1302,7 @@ static const struct generic_data set_le_on_success_test_1 = {
 };
 
 static const struct generic_data set_le_on_success_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_LE,
        .send_param = set_le_on_param,
        .send_len = sizeof(set_le_on_param),
@@ -1018,6 +1316,7 @@ static const struct generic_data set_le_on_success_test_2 = {
 };
 
 static const struct generic_data set_le_on_success_test_3 = {
+       .setup_settings = settings_le,
        .send_opcode = MGMT_OP_SET_POWERED,
        .send_param = set_powered_on_param,
        .send_len = sizeof(set_powered_on_param),
@@ -1057,12 +1356,16 @@ static const struct generic_data set_le_on_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static uint16_t settings_powered_le[] = { MGMT_OP_SET_LE,
+                                       MGMT_OP_SET_POWERED, 0 };
+
 static const char set_adv_on_param[] = { 0x01 };
 static const char set_adv_settings_param_1[] = { 0x80, 0x06, 0x00, 0x00 };
 static const char set_adv_settings_param_2[] = { 0x81, 0x06, 0x00, 0x00 };
 static const char set_adv_on_set_adv_enable_param[] = { 0x01 };
 
 static const struct generic_data set_adv_on_success_test_1 = {
+       .setup_settings = settings_le,
        .send_opcode = MGMT_OP_SET_ADVERTISING,
        .send_param = set_adv_on_param,
        .send_len = sizeof(set_adv_on_param),
@@ -1073,6 +1376,7 @@ static const struct generic_data set_adv_on_success_test_1 = {
 };
 
 static const struct generic_data set_adv_on_success_test_2 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_SET_ADVERTISING,
        .send_param = set_adv_on_param,
        .send_len = sizeof(set_adv_on_param),
@@ -1086,6 +1390,7 @@ static const struct generic_data set_adv_on_success_test_2 = {
 };
 
 static const struct generic_data set_adv_on_rejected_test_1 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_ADVERTISING,
        .send_param = set_adv_on_param,
        .send_len = sizeof(set_adv_on_param),
@@ -1100,6 +1405,7 @@ static const char set_bredr_settings_param_2[] = { 0x80, 0x02, 0x00, 0x00 };
 static const char set_bredr_settings_param_3[] = { 0x81, 0x02, 0x00, 0x00 };
 
 static const struct generic_data set_bredr_off_success_test_1 = {
+       .setup_settings = settings_le,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_off_param,
        .send_len = sizeof(set_bredr_off_param),
@@ -1110,6 +1416,8 @@ static const struct generic_data set_bredr_off_success_test_1 = {
 };
 
 static const struct generic_data set_bredr_on_success_test_1 = {
+       .setup_settings = settings_le,
+       .setup_nobredr = true,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_on_param,
        .send_len = sizeof(set_bredr_on_param),
@@ -1120,6 +1428,8 @@ static const struct generic_data set_bredr_on_success_test_1 = {
 };
 
 static const struct generic_data set_bredr_on_success_test_2 = {
+       .setup_settings = settings_powered_le,
+       .setup_nobredr = true,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_on_param,
        .send_len = sizeof(set_bredr_on_param),
@@ -1137,6 +1447,7 @@ static const struct generic_data set_bredr_off_notsupp_test = {
 };
 
 static const struct generic_data set_bredr_off_failure_test_1 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_off_param,
        .send_len = sizeof(set_bredr_off_param),
@@ -1144,6 +1455,7 @@ static const struct generic_data set_bredr_off_failure_test_1 = {
 };
 
 static const struct generic_data set_bredr_off_failure_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_off_param,
        .send_len = sizeof(set_bredr_off_param),
@@ -1151,12 +1463,16 @@ static const struct generic_data set_bredr_off_failure_test_2 = {
 };
 
 static const struct generic_data set_bredr_off_failure_test_3 = {
+       .setup_settings = settings_le,
        .send_opcode = MGMT_OP_SET_BREDR,
        .send_param = set_bredr_invalid_param,
        .send_len = sizeof(set_bredr_invalid_param),
        .expect_status = MGMT_STATUS_INVALID_PARAMS,
 };
 
+static uint16_t settings_powered_ssp[] = { MGMT_OP_SET_SSP,
+                                               MGMT_OP_SET_POWERED, 0 };
+
 static const char set_local_name_param[260] = { 'T', 'e', 's', 't', ' ',
                                                'n', 'a', 'm', 'e' };
 static const char write_local_name_hci[248] = { 'T', 'e', 's', 't', ' ',
@@ -1178,6 +1494,7 @@ static const struct generic_data set_local_name_test_1 = {
 };
 
 static const struct generic_data set_local_name_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_LOCAL_NAME,
        .send_param = set_local_name_param,
        .send_len = sizeof(set_local_name_param),
@@ -1193,6 +1510,7 @@ static const struct generic_data set_local_name_test_2 = {
 };
 
 static const struct generic_data set_local_name_test_3 = {
+       .setup_settings = settings_powered_ssp,
        .send_opcode = MGMT_OP_SET_LOCAL_NAME,
        .send_param = set_local_name_param,
        .send_len = sizeof(set_local_name_param),
@@ -1223,6 +1541,7 @@ static const struct generic_data start_discovery_not_powered_test_1 = {
 };
 
 static const struct generic_data start_discovery_invalid_param_test_1 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_START_DISCOVERY,
        .send_param = start_discovery_invalid_param,
        .send_len = sizeof(start_discovery_invalid_param),
@@ -1230,6 +1549,7 @@ static const struct generic_data start_discovery_invalid_param_test_1 = {
 };
 
 static const struct generic_data start_discovery_not_supported_test_1 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_START_DISCOVERY,
        .send_param = start_discovery_le_param,
        .send_len = sizeof(start_discovery_le_param),
@@ -1237,6 +1557,7 @@ static const struct generic_data start_discovery_not_supported_test_1 = {
 };
 
 static const struct generic_data start_discovery_valid_param_test_1 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_START_DISCOVERY,
        .send_param = start_discovery_bredrle_param,
        .send_len = sizeof(start_discovery_bredrle_param),
@@ -1252,6 +1573,7 @@ static const struct generic_data start_discovery_valid_param_test_1 = {
 };
 
 static const struct generic_data start_discovery_valid_param_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_START_DISCOVERY,
        .send_param = start_discovery_le_param,
        .send_len = sizeof(start_discovery_le_param),
@@ -1275,6 +1597,7 @@ static const char stop_discovery_bredr_discovering[] = { 0x01, 0x00 };
 static const char stop_discovery_inq_param[] = { 0x33, 0x8b, 0x9e, 0x08, 0x00 };
 
 static const struct generic_data stop_discovery_success_test_1 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_STOP_DISCOVERY,
        .send_param = stop_discovery_bredrle_param,
        .send_len = sizeof(stop_discovery_bredrle_param),
@@ -1290,6 +1613,7 @@ static const struct generic_data stop_discovery_success_test_1 = {
 };
 
 static const struct generic_data stop_discovery_bredr_success_test_1 = {
+       .setup_settings = settings_powered_le,
        .setup_expect_hci_command = BT_HCI_CMD_INQUIRY,
        .setup_expect_hci_param = stop_discovery_inq_param,
        .setup_expect_hci_len = sizeof(stop_discovery_inq_param),
@@ -1306,6 +1630,7 @@ static const struct generic_data stop_discovery_bredr_success_test_1 = {
 };
 
 static const struct generic_data stop_discovery_rejected_test_1 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_STOP_DISCOVERY,
        .send_param = stop_discovery_bredrle_param,
        .send_len = sizeof(stop_discovery_bredrle_param),
@@ -1315,6 +1640,7 @@ static const struct generic_data stop_discovery_rejected_test_1 = {
 };
 
 static const struct generic_data stop_discovery_invalid_param_test_1 = {
+       .setup_settings = settings_powered_le,
        .send_opcode = MGMT_OP_STOP_DISCOVERY,
        .send_param = stop_discovery_bredrle_invalid_param,
        .send_len = sizeof(stop_discovery_bredrle_invalid_param),
@@ -1339,6 +1665,7 @@ static const struct generic_data set_dev_class_valid_param_test_1 = {
 };
 
 static const struct generic_data set_dev_class_valid_param_test_2 = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_DEV_CLASS,
        .send_param = set_dev_class_valid_param,
        .send_len = sizeof(set_dev_class_valid_param),
@@ -1525,6 +1852,7 @@ static const char write_eir_uuid_mix_hci[241] = { 0x00,
                        0x44, 0x33, 0x22, 0x11 };
 
 static const struct generic_data add_uuid16_test_1 = {
+       .setup_settings = settings_powered_ssp,
        .send_opcode = MGMT_OP_ADD_UUID,
        .send_param = add_spp_uuid_param,
        .send_len = sizeof(add_spp_uuid_param),
@@ -1561,6 +1889,7 @@ static const struct generic_data add_multi_uuid16_test_2 = {
 };
 
 static const struct generic_data add_uuid32_test_1 = {
+       .setup_settings = settings_powered_ssp,
        .send_opcode = MGMT_OP_ADD_UUID,
        .send_param = add_uuid32_param_1,
        .send_len = sizeof(add_uuid32_param_1),
@@ -1597,6 +1926,7 @@ static const struct generic_data add_uuid32_multi_test_2 = {
 };
 
 static const struct generic_data add_uuid128_test_1 = {
+       .setup_settings = settings_powered_ssp,
        .send_opcode = MGMT_OP_ADD_UUID,
        .send_param = add_uuid128_param_1,
        .send_len = sizeof(add_uuid128_param_1),
@@ -1891,6 +2221,7 @@ static const struct generic_data set_static_addr_success_test = {
 };
 
 static const struct generic_data set_static_addr_failure_test = {
+       .setup_settings = settings_powered,
        .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
        .send_param = set_static_addr_valid_param,
        .send_len = sizeof(set_static_addr_valid_param),
@@ -1906,11 +2237,6 @@ static const struct generic_data set_scan_params_success_test = {
        .expect_status = MGMT_STATUS_SUCCESS,
 };
 
-static void powered_delay(void *user_data)
-{
-       tester_setup_complete();
-}
-
 static void setup_powered_callback(uint8_t status, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -1921,47 +2247,7 @@ static void setup_powered_callback(uint8_t status, uint16_t length,
 
        tester_print("Controller powered on");
 
-       if (option_wait_powered)
-               tester_wait(1, powered_delay, NULL);
-       else
-               tester_setup_complete();
-}
-
-static void setup_powered_discoverable(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-       unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
-
-       tester_print("Enabling connectable, discoverable and powered");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
-                                       sizeof(param), param,
-                                       NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_DISCOVERABLE, data->mgmt_index,
-                                       sizeof(discov_param), discov_param,
-                                       NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
-}
-
-static void setup_powered_connectable(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Enabling connectable and powered");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
-                                       sizeof(param), param,
-                                       NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
+       tester_setup_complete();
 }
 
 static void setup_class(const void *test_data)
@@ -1981,54 +2267,6 @@ static void setup_class(const void *test_data)
                                        setup_powered_callback, NULL, NULL);
 }
 
-static void setup_ssp_powered(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Powering on controller (with SSP enabled)");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
-                               sizeof(param), param, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
-}
-
-static void setup_le_powered(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Powering on controller (with LE enabled)");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
-                               sizeof(param), param, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
-}
-
-static void setup_le_nobr_powered(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char on[] = { 0x01 };
-       unsigned char off[] = { 0x00 };
-
-       tester_print("Powering on controller (with LE enabled)");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
-                               sizeof(on), on, NULL, NULL, NULL);
-       mgmt_send(data->mgmt, MGMT_OP_SET_BREDR, data->mgmt_index,
-                               sizeof(off), off, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(on), on,
-                                       setup_powered_callback, NULL, NULL);
-}
-
 static void setup_discovery_callback(uint8_t status, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -2071,19 +2309,11 @@ done:
        return false;
 }
 
-static void setup_start_discovery_callback(uint8_t status, uint16_t length,
-                                       const void *param, void *user_data)
+static void setup_start_discovery(const void *test_data)
 {
        struct test_data *data = tester_get_data();
        const struct generic_data *test = data->test_data;
 
-       if (status != MGMT_STATUS_SUCCESS) {
-               tester_setup_failed();
-               return;
-       }
-
-       tester_print("Controller powered on");
-
        if (test->setup_expect_hci_command) {
                tester_print("Registering HCI command callback (setup)");
                hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_EVT,
@@ -2100,90 +2330,6 @@ static void setup_start_discovery_callback(uint8_t status, uint16_t length,
                                        sizeof(disc_param), disc_param,
                                        setup_discovery_callback, NULL, NULL);
        }
-
-       if (option_wait_powered)
-               tester_wait(1, NULL, NULL);
-}
-
-static void setup_start_discovery(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Powering on controller (with LE enabled)");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
-                               sizeof(param), param, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                               sizeof(param), param,
-                               setup_start_discovery_callback, NULL, NULL);
-}
-
-static void setup_ssp_callback(uint8_t status, uint16_t length,
-                                       const void *param, void *user_data)
-{
-       if (status != MGMT_STATUS_SUCCESS) {
-               tester_setup_failed();
-               return;
-       }
-
-       tester_print("SSP enabled");
-
-       tester_setup_complete();
-}
-
-static void setup_ssp(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Enabling SSP");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
-                               sizeof(param), param, setup_ssp_callback,
-                               NULL, NULL);
-}
-
-static void setup_le_callback(uint8_t status, uint16_t length,
-                                       const void *param, void *user_data)
-{
-       if (status != MGMT_STATUS_SUCCESS) {
-               tester_setup_failed();
-               return;
-       }
-
-       tester_print("Low Energy enabled");
-
-       tester_setup_complete();
-}
-
-static void setup_le(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Enabling Low Energy");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
-                               sizeof(param), param, setup_le_callback,
-                               NULL, NULL);
-}
-
-static void setup_le_nobr(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char on[] = { 0x01 };
-       unsigned char off[] = { 0x00 };
-
-       tester_print("Enabling Low Energy");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
-                               sizeof(on), on, NULL,
-                               NULL, NULL);
-       mgmt_send(data->mgmt, MGMT_OP_SET_BREDR, data->mgmt_index,
-                               sizeof(off), off, setup_le_callback,
-                               NULL, NULL);
 }
 
 static void setup_multi_uuid32(const void *test_data)
@@ -2370,96 +2516,69 @@ static void setup_uuid_mix(const void *test_data)
                                        setup_powered_callback, NULL, NULL);
 }
 
-static void setup_powered(const void *test_data)
+static void setup_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
        struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Powering on controller");
 
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
-}
-
-static void setup_connectable_callback(uint8_t status, uint16_t length,
-                                       const void *param, void *user_data)
-{
        if (status != MGMT_STATUS_SUCCESS) {
                tester_setup_failed();
                return;
        }
 
-       tester_print("Controller connectable on");
-
-       tester_setup_complete();
-}
-
-static void setup_connectable(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Setting controller connectable");
+       tester_print("Initial settings completed");
 
-       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_connectable_callback, NULL, NULL);
+       if (data->test_setup)
+               data->test_setup(data);
+       else
+               tester_setup_complete();
 }
 
-static void setup_connectable_powered(const void *test_data)
+static void test_setup(const void *test_data)
 {
        struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Setting controller powered and connectable");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
-                       sizeof(param), param, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
-}
+       const struct generic_data *test = data->test_data;
+       const uint16_t *cmd;
 
-static void setup_link_sec_callback(uint8_t status, uint16_t length,
-                                       const void *param, void *user_data)
-{
-       if (status != MGMT_STATUS_SUCCESS) {
-               tester_setup_failed();
+       if (!test || !test->setup_settings) {
+               if (data->test_setup)
+                       data->test_setup(data);
+               else
+                       tester_setup_complete();
                return;
        }
 
-       tester_print("Link security enabled");
-
-       tester_setup_complete();
-}
-
-static void setup_link_sec(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Enabling link security");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LINK_SECURITY, data->mgmt_index,
-                       sizeof(param), param, setup_link_sec_callback,
-                       NULL, NULL);
-}
-
-static void setup_link_sec_powered(const void *test_data)
-{
-       struct test_data *data = tester_get_data();
-       unsigned char param[] = { 0x01 };
-
-       tester_print("Enabling link security and powering on");
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_LINK_SECURITY, data->mgmt_index,
-                       sizeof(param), param, NULL, NULL, NULL);
-
-       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
-                                       sizeof(param), param,
-                                       setup_powered_callback, NULL, NULL);
+       for (cmd = test->setup_settings; *cmd; cmd++) {
+               unsigned char simple_param[] = { 0x01 };
+               unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
+               unsigned char *param = simple_param;
+               size_t param_size = sizeof(simple_param);
+               mgmt_request_func_t func = NULL;
+
+               /* If this is the last command (next one is 0) request
+                * for a callback. */
+               if (!cmd[1])
+                       func = setup_complete;
+
+               if (*cmd == MGMT_OP_SET_DISCOVERABLE) {
+                       if (test->setup_limited_discov) {
+                               discov_param[0] = 0x02;
+                               discov_param[1] = 0x01;
+                       }
+                       param_size = sizeof(discov_param);
+                       param = discov_param;
+               }
+
+               mgmt_send(data->mgmt, *cmd, data->mgmt_index,
+                               param_size, param, func, data, NULL);
+
+               if (*cmd == MGMT_OP_SET_LE && test->setup_nobredr) {
+                       unsigned char off[] = { 0x00 };
+                       mgmt_send(data->mgmt, MGMT_OP_SET_BREDR,
+                                       data->mgmt_index, sizeof(off), off,
+                                       NULL, data, NULL);
+               }
+       }
 }
 
 static void command_generic_new_settings(uint16_t index, uint16_t length,
@@ -2639,39 +2758,15 @@ static void test_command_generic(const void *test_data)
        test_add_condition(data);
 }
 
-static GOptionEntry options[] = {
-       { "wait-powered", 'P', 0, G_OPTION_ARG_NONE, &option_wait_powered,
-                                       "Add a delay after powering on" },
-       { NULL },
-};
-
 int main(int argc, char *argv[])
 {
-       GOptionContext *context;
-       GError *error = NULL;
-
-       context = g_option_context_new(NULL);
-       g_option_context_add_main_entries(context, options, NULL);
-       g_option_context_set_ignore_unknown_options(context, TRUE);
-
-       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
-               if (error != NULL) {
-                       g_printerr("%s\n", error->message);
-                       g_error_free(error);
-               } else
-                       g_printerr("An unknown error occurred\n");
-               exit(1);
-       }
-
-       g_option_context_free(context);
-
        tester_init(&argc, &argv);
 
        test_bredrle("Controller setup",
                                NULL, NULL, controller_setup);
        test_bredr("Controller setup (BR/EDR-only)",
                                NULL, NULL, controller_setup);
-       test_le("Controller setup (LE-only)",
+       test_le("Controller setup (LE)",
                                NULL, NULL, controller_setup);
 
        test_bredrle("Invalid command",
@@ -2724,26 +2819,26 @@ int main(int argc, char *argv[])
 
        test_bredrle("Set powered off - Success",
                                &set_powered_off_success_test,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set powered off - Class of Device",
                                &set_powered_off_class_test,
                                setup_class, test_command_generic);
        test_bredrle("Set powered off - Invalid parameters 1",
                                &set_powered_off_invalid_param_test_1,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set powered off - Invalid parameters 2",
                                &set_powered_off_invalid_param_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set powered off - Invalid parameters 3",
                                &set_powered_off_invalid_param_test_3,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Set connectable on - Success 1",
                                &set_connectable_on_success_test_1,
                                NULL, test_command_generic);
        test_bredrle("Set connectable on - Success 2",
                                &set_connectable_on_success_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set connectable on - Invalid parameters 1",
                                &set_connectable_on_invalid_param_test_1,
                                NULL, test_command_generic);
@@ -2757,16 +2852,45 @@ int main(int argc, char *argv[])
                                &set_connectable_on_invalid_index_test,
                                NULL, test_command_generic);
 
+       test_le("Set connectable on (LE) - Success 1",
+                               &set_connectable_on_le_test_1,
+                               NULL, test_command_generic);
+       test_le("Set connectable on (LE) - Success 2",
+                               &set_connectable_on_le_test_2,
+                               NULL, test_command_generic);
+       test_le("Set connectable on (LE) - Success 3",
+                               &set_connectable_on_le_test_3,
+                               NULL, test_command_generic);
+
        test_bredrle("Set connectable off - Success 1",
-                       &set_connectable_off_success_test_1,
-                       setup_connectable, test_command_generic);
+                               &set_connectable_off_success_test_1,
+                               NULL, test_command_generic);
        test_bredrle("Set connectable off - Success 2",
-                       &set_connectable_off_success_test_2,
-                       setup_connectable_powered, test_command_generic);
+                               &set_connectable_off_success_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set connectable off - Success 3",
+                               &set_connectable_off_success_test_3,
+                               NULL, test_command_generic);
+
+       test_le("Set connectable off (LE) - Success 1",
+                               &set_connectable_off_le_test_1,
+                               NULL, test_command_generic);
+       test_le("Set connectable off (LE) - Success 2",
+                               &set_connectable_off_le_test_2,
+                               NULL, test_command_generic);
+       test_le("Set connectable off (LE) - Success 3",
+                               &set_connectable_off_le_test_3,
+                               NULL, test_command_generic);
+       test_le("Set connectable off (LE) - Success 4",
+                               &set_connectable_off_le_test_4,
+                               NULL, test_command_generic);
 
        test_bredrle("Set fast connectable on - Success 1",
-                       &set_fast_conn_on_success_test_1,
-                       setup_powered_connectable, test_command_generic);
+                               &set_fast_conn_on_success_test_1,
+                               NULL, test_command_generic);
+       test_le("Set fast connectable on - Not Supported 1",
+                               &set_fast_conn_on_not_supported_test_1,
+                               NULL, test_command_generic);
 
        test_bredrle("Set pairable on - Success",
                                &set_pairable_on_success_test,
@@ -2799,44 +2923,55 @@ int main(int argc, char *argv[])
        test_bredrle("Set discoverable on - Not powered 1",
                                &set_discoverable_on_not_powered_test_1,
                                NULL, test_command_generic);
-       test_bredrle("Set discoverable on - Not powered 1",
-                               &set_discoverable_on_not_powered_test_1,
-                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Not powered 2",
-                               &set_discoverable_on_not_powered_test_1,
-                               setup_connectable, test_command_generic);
+                               &set_discoverable_on_not_powered_test_2,
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Rejected 1",
                                &set_discoverable_on_rejected_test_1,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Rejected 2",
                                &set_discoverable_on_rejected_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Rejected 3",
                                &set_discoverable_on_rejected_test_3,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Success 1",
                                &set_discoverable_on_success_test_1,
-                               setup_connectable, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable on - Success 2",
                                &set_discoverable_on_success_test_2,
-                               setup_powered_connectable, test_command_generic);
+                               NULL, test_command_generic);
+       test_le("Set discoverable on (LE) - Success 1",
+                               &set_discov_on_le_success_1,
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable off - Success 1",
                                &set_discoverable_off_success_test_1,
-                               setup_connectable, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set discoverable off - Success 2",
                                &set_discoverable_off_success_test_2,
-                               setup_powered_discoverable,
-                               test_command_generic);
+                               NULL, test_command_generic);
+       test_bredrle("Set limited discoverable on - Success 1",
+                               &set_limited_discov_on_success_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set limited discoverable on - Success 2",
+                               &set_limited_discov_on_success_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set limited discoverable on - Success 3",
+                               &set_limited_discov_on_success_3,
+                               NULL, test_command_generic);
+       test_le("Set limited discoverable on (LE) - Success 1",
+                               &set_limited_discov_on_le_success_1,
+                               NULL, test_command_generic);
 
        test_bredrle("Set link security on - Success 1",
                                &set_link_sec_on_success_test_1,
                                NULL, test_command_generic);
        test_bredrle("Set link security on - Success 2",
                                &set_link_sec_on_success_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set link security on - Success 3",
                                &set_link_sec_on_success_test_3,
-                               setup_link_sec, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set link security on - Invalid parameters 1",
                                &set_link_sec_on_invalid_param_test_1,
                                NULL, test_command_generic);
@@ -2852,20 +2987,20 @@ int main(int argc, char *argv[])
 
        test_bredrle("Set link security off - Success 1",
                                &set_link_sec_off_success_test_1,
-                               setup_link_sec, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set link security off - Success 2",
                                &set_link_sec_off_success_test_2,
-                               setup_link_sec_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Set SSP on - Success 1",
                                &set_ssp_on_success_test_1,
                                NULL, test_command_generic);
        test_bredrle("Set SSP on - Success 2",
                                &set_ssp_on_success_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set SSP on - Success 3",
                                &set_ssp_on_success_test_3,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set SSP on - Invalid parameters 1",
                                &set_ssp_on_invalid_param_test_1,
                                NULL, test_command_generic);
@@ -2881,29 +3016,29 @@ int main(int argc, char *argv[])
 
        test_bredrle("Set High Speed on - Success",
                                &set_hs_on_success_test,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set High Speed on - Invalid parameters 1",
                                &set_hs_on_invalid_param_test_1,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set High Speed on - Invalid parameters 2",
                                &set_hs_on_invalid_param_test_2,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set High Speed on - Invalid parameters 3",
                                &set_hs_on_invalid_param_test_3,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set High Speed on - Invalid index",
                                &set_hs_on_invalid_index_test,
-                               setup_ssp, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Set Low Energy on - Success 1",
                                &set_le_on_success_test_1,
                                NULL, test_command_generic);
        test_bredrle("Set Low Energy on - Success 2",
                                &set_le_on_success_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set Low Energy on - Success 3",
                                &set_le_on_success_test_3,
-                               setup_le, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set Low Energy on - Invalid parameters 1",
                                &set_le_on_invalid_param_test_1,
                                NULL, test_command_generic);
@@ -2919,23 +3054,23 @@ int main(int argc, char *argv[])
 
        test_bredrle("Set Advertising on - Success 1",
                                &set_adv_on_success_test_1,
-                               setup_le, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set Advertising on - Success 2",
                                &set_adv_on_success_test_2,
-                               setup_le_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set Advertising on - Rejected 1",
                                &set_adv_on_rejected_test_1,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Set BR/EDR off - Success 1",
                                &set_bredr_off_success_test_1,
-                               setup_le, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set BR/EDR on - Success 1",
                                &set_bredr_on_success_test_1,
-                               setup_le_nobr, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set BR/EDR on - Success 2",
                                &set_bredr_on_success_test_2,
-                               setup_le_nobr_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredr("Set BR/EDR off - Not Supported 1",
                                &set_bredr_off_notsupp_test,
                                NULL, test_command_generic);
@@ -2944,39 +3079,39 @@ int main(int argc, char *argv[])
                                NULL, test_command_generic);
        test_bredrle("Set BR/EDR off - Rejected 1",
                                &set_bredr_off_failure_test_1,
-                               setup_le_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set BR/EDR off - Rejected 2",
                                &set_bredr_off_failure_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set BR/EDR off - Invalid Parameters 1",
                                &set_bredr_off_failure_test_3,
-                               setup_le, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredr("Set Local Name - Success 1",
                                &set_local_name_test_1,
                                NULL, test_command_generic);
        test_bredr("Set Local Name - Success 2",
                                &set_local_name_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredr("Set Local Name - Success 3",
                                &set_local_name_test_3,
-                               setup_ssp_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Start Discovery - Not powered 1",
                                &start_discovery_not_powered_test_1,
                                NULL, test_command_generic);
        test_bredrle("Start Discovery - Invalid parameters 1",
                                &start_discovery_invalid_param_test_1,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Start Discovery - Not supported 1",
                                &start_discovery_not_supported_test_1,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Start Discovery - Success 1",
                                &start_discovery_valid_param_test_1,
-                               setup_le_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_le("Start Discovery - Success 2",
                                &start_discovery_valid_param_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Stop Discovery - Success 1",
                                &stop_discovery_success_test_1,
@@ -2986,7 +3121,7 @@ int main(int argc, char *argv[])
                                setup_start_discovery, test_command_generic);
        test_bredrle("Stop Discovery - Rejected 1",
                                &stop_discovery_rejected_test_1,
-                               setup_le_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Stop Discovery - Invalid parameters 1",
                                &stop_discovery_invalid_param_test_1,
                                setup_start_discovery, test_command_generic);
@@ -2996,14 +3131,14 @@ int main(int argc, char *argv[])
                                NULL, test_command_generic);
        test_bredrle("Set Device Class - Success 2",
                                &set_dev_class_valid_param_test_2,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Set Device Class - Invalid parameters 1",
                                &set_dev_class_invalid_param_test_1,
                                NULL, test_command_generic);
 
        test_bredrle("Add UUID - UUID-16 1",
                                &add_uuid16_test_1,
-                               setup_ssp_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Add UUID - UUID-16 multiple 1",
                                &add_multi_uuid16_test_1,
                                setup_multi_uuid16, test_command_generic);
@@ -3012,7 +3147,7 @@ int main(int argc, char *argv[])
                                setup_multi_uuid16_2, test_command_generic);
        test_bredrle("Add UUID - UUID-32 1",
                                &add_uuid32_test_1,
-                               setup_ssp_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Add UUID - UUID-32 multiple 1",
                                &add_uuid32_multi_test_1,
                                setup_multi_uuid32, test_command_generic);
@@ -3021,7 +3156,7 @@ int main(int argc, char *argv[])
                                setup_multi_uuid32_2, test_command_generic);
        test_bredrle("Add UUID - UUID-128 1",
                                &add_uuid128_test_1,
-                               setup_ssp_powered, test_command_generic);
+                               NULL, test_command_generic);
        test_bredrle("Add UUID - UUID-128 multiple 1",
                                &add_uuid128_multi_test_1,
                                setup_multi_uuid128, test_command_generic);
@@ -3098,7 +3233,7 @@ int main(int argc, char *argv[])
                                NULL, test_command_generic);
        test_bredrle("Set Static Address - Failure",
                                &set_static_addr_failure_test,
-                               setup_powered, test_command_generic);
+                               NULL, test_command_generic);
 
        test_bredrle("Set Scan Parameters - Success",
                                &set_scan_params_success_test,
diff --git a/tools/smp-tester.c b/tools/smp-tester.c
new file mode 100644 (file)
index 0000000..46dc65a
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hciemu.h"
+
+#define SMP_CID 0x0006
+
+struct test_data {
+       const void *test_data;
+       struct mgmt *mgmt;
+       uint16_t mgmt_index;
+       struct hciemu *hciemu;
+       enum hciemu_type hciemu_type;
+       unsigned int io_id;
+       uint16_t handle;
+};
+
+struct smp_server_data {
+       const void *send_req;
+       uint16_t send_req_len;
+       const void *expect_rsp;
+       uint16_t expect_rsp_len;
+};
+
+struct smp_client_data {
+       const void *expect_req;
+       uint16_t expect_req_len;
+       const void *send_rsp;
+       uint16_t send_rsp_len;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct mgmt_rp_read_info *rp = param;
+       char addr[18];
+       uint16_t manufacturer;
+       uint32_t supported_settings, current_settings;
+
+       tester_print("Read Info callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+       manufacturer = btohs(rp->manufacturer);
+       supported_settings = btohl(rp->supported_settings);
+       current_settings = btohl(rp->current_settings);
+
+       tester_print("  Address: %s", addr);
+       tester_print("  Version: 0x%02x", rp->version);
+       tester_print("  Manufacturer: 0x%04x", manufacturer);
+       tester_print("  Supported settings: 0x%08x", supported_settings);
+       tester_print("  Current settings: 0x%08x", current_settings);
+       tester_print("  Class: 0x%02x%02x%02x",
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+       tester_print("  Name: %s", rp->name);
+       tester_print("  Short name: %s", rp->short_name);
+
+       if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Added callback");
+       tester_print("  Index: 0x%04x", index);
+
+       data->mgmt_index = index;
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+                                       read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Removed callback");
+       tester_print("  Index: 0x%04x", index);
+
+       if (index != data->mgmt_index)
+               return;
+
+       mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+       mgmt_unref(data->mgmt);
+       data->mgmt = NULL;
+
+       tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Read Index List callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                       index_added_callback, NULL, NULL);
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                       index_removed_callback, NULL, NULL);
+
+       data->hciemu = hciemu_new(data->hciemu_type);
+       if (!data->hciemu) {
+               tester_warn("Failed to setup HCI emulation");
+               tester_pre_setup_failed();
+       }
+
+       tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       data->mgmt = mgmt_new_default();
+       if (!data->mgmt) {
+               tester_warn("Failed to setup management interface");
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (tester_use_debug())
+               mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+                                       read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       if (data->io_id > 0) {
+               g_source_remove(data->io_id);
+               data->io_id = 0;
+       }
+
+       hciemu_unref(data->hciemu);
+       data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+       struct test_data *data = test_data;
+
+       free(data);
+}
+
+#define test_smp(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_LE; \
+               user->io_id = 0; \
+               user->test_data = data; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, test_data_free); \
+       } while (0)
+
+static const uint8_t smp_nval_req_1[] = { 0x0b, 0x00 };
+static const uint8_t smp_nval_req_1_rsp[] = { 0x05, 0x07 };
+
+static const struct smp_server_data smp_server_nval_req_1_test = {
+       .send_req = smp_nval_req_1,
+       .send_req_len = sizeof(smp_nval_req_1),
+       .expect_rsp = smp_nval_req_1_rsp,
+       .expect_rsp_len = sizeof(smp_nval_req_1_rsp),
+};
+
+static const uint8_t smp_nval_req_2[7] = { 0x01 };
+static const uint8_t smp_nval_req_2_rsp[] = { 0x05, 0x06 };
+
+static const struct smp_server_data smp_server_nval_req_2_test = {
+       .send_req = smp_nval_req_2,
+       .send_req_len = sizeof(smp_nval_req_2),
+       .expect_rsp = smp_nval_req_2_rsp,
+       .expect_rsp_len = sizeof(smp_nval_req_2_rsp),
+};
+
+static const uint8_t smp_basic_req_1[] = {     0x01,   /* Pairing Request */
+                                               0x03,   /* NoInputNoOutput */
+                                               0x00,   /* OOB Flag */
+                                               0x01,   /* Bonding - no MITM */
+                                               0x10,   /* Max key size */
+                                               0x00,   /* Init. key dist. */
+                                               0x01,   /* Rsp. key dist. */
+
+};
+static const uint8_t smp_basic_req_1_rsp[] = { 0x02,   /* Pairing Response */
+                                               0x03,   /* NoInputNoOutput */
+                                               0x00,   /* OOB Flag */
+                                               0x00,   /* SMP auth none */
+                                               0x10,   /* Max key size */
+                                               0x00,   /* Init. key dist. */
+                                               0x00,   /* Rsp. key dist. */
+
+};
+
+static const struct smp_server_data smp_server_basic_req_1_test = {
+       .send_req = smp_basic_req_1,
+       .send_req_len = sizeof(smp_basic_req_1),
+       .expect_rsp = smp_basic_req_1_rsp,
+       .expect_rsp_len = sizeof(smp_basic_req_1_rsp),
+};
+
+static const struct smp_client_data smp_client_basic_req_1_test = {
+       .expect_req = smp_basic_req_1,
+       .expect_req_len = sizeof(smp_basic_req_1),
+};
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+                                       const void *param, uint8_t len,
+                                       void *user_data)
+{
+       if (opcode != BT_HCI_CMD_LE_SET_ADV_ENABLE)
+               return;
+
+       tester_print("Client set connectable status 0x%02x", status);
+
+       if (status)
+               tester_setup_failed();
+       else
+               tester_setup_complete();
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       struct bthost *bthost;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
+       bthost_set_adv_enable(bthost, 0x01);
+}
+
+static void setup_powered_client(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_PAIRABLE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                       sizeof(param), param, setup_powered_client_callback,
+                       NULL, NULL);
+}
+
+static void pair_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_warn("Pairing failed: %s", mgmt_errstr(status));
+               tester_test_failed();
+               return;
+       }
+
+       tester_print("Pairing succeedded");
+       tester_test_passed();
+}
+
+static void smp_server(const void *data, uint16_t len, void *user_data)
+{
+       struct test_data *test_data = tester_get_data();
+       const struct smp_client_data *cli = test_data->test_data;
+
+       tester_print("Received SMP request");
+
+       if (!cli->expect_req) {
+               tester_test_passed();
+               return;
+       }
+
+       if (cli->expect_req_len != len) {
+               tester_warn("Unexpected SMP request length (%u != %u)",
+                                               len, cli->expect_req_len);
+               goto failed;
+       }
+
+       if (memcmp(cli->expect_req, data, len) != 0) {
+               tester_warn("Unexpected SMP request");
+               goto failed;
+       }
+
+       if (cli->send_rsp) {
+               struct bthost *bthost;
+
+               bthost = hciemu_client_get_host(test_data->hciemu);
+               bthost_send_cid(bthost, test_data->handle, SMP_CID,
+                                       cli->send_rsp, cli->send_rsp_len);
+               return;
+       }
+
+       tester_test_passed();
+       return;
+
+failed:
+       tester_test_failed();
+}
+
+static void smp_server_new_conn(uint16_t handle, void *user_data)
+{
+       struct test_data *data = user_data;
+       struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+       tester_print("New server connection with handle 0x%04x", handle);
+
+       data->handle = handle;
+
+       bthost_add_cid_hook(bthost, handle, SMP_CID, smp_server, NULL);
+}
+
+static void test_client(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const uint8_t *client_bdaddr;
+       struct mgmt_cp_pair_device cp;
+       struct bthost *bthost;
+
+       client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+       if (!client_bdaddr) {
+               tester_warn("No client bdaddr");
+               tester_test_failed();
+               return;
+       }
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_connect_cb(bthost, smp_server_new_conn, data);
+
+       memcpy(&cp.addr.bdaddr, client_bdaddr, sizeof(bdaddr_t));
+       cp.addr.type = BDADDR_LE_PUBLIC;
+       cp.io_cap = 0x03; /* NoInputNoOutput */
+
+       mgmt_send(data->mgmt, MGMT_OP_PAIR_DEVICE, data->mgmt_index,
+                       sizeof(cp), &cp, pair_device_complete, NULL, NULL);
+
+       tester_print("Pairing in progress");
+}
+
+static void setup_powered_server_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       tester_setup_complete();
+}
+
+static void setup_powered_server(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                       sizeof(param), param, setup_powered_server_callback,
+                       NULL, NULL);
+}
+
+static void smp_client(const void *data, uint16_t len, void *user_data)
+{
+       struct test_data *test_data = user_data;
+       const struct smp_server_data *srv = test_data->test_data;
+
+       tester_print("SMP client received response");
+
+       if (!srv->expect_rsp) {
+               tester_test_passed();
+               return;
+       }
+
+       if (srv->expect_rsp_len != len) {
+               tester_warn("Unexpected SMP response length (%u != %u)",
+                                               len, srv->expect_rsp_len);
+               goto failed;
+       }
+
+       if (memcmp(srv->expect_rsp, data, len) != 0) {
+               tester_warn("Unexpected SMP response");
+               goto failed;
+       }
+
+       tester_test_passed();
+       return;
+
+failed:
+       tester_test_failed();
+}
+
+static void smp_client_new_conn(uint16_t handle, void *user_data)
+{
+       struct test_data *data = user_data;
+       const struct smp_server_data *srv = data->test_data;
+       struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+       tester_print("New SMP client connection with handle 0x%04x", handle);
+
+       bthost_add_cid_hook(bthost, handle, SMP_CID, smp_client, data);
+
+       if (!srv->send_req)
+               return;
+
+       tester_print("Sending SMP Request from client");
+
+       bthost_send_cid(bthost, handle, SMP_CID, srv->send_req,
+                                                       srv->send_req_len);
+}
+
+static void test_server(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const uint8_t *master_bdaddr;
+       struct bthost *bthost;
+
+       master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+       if (!master_bdaddr) {
+               tester_warn("No master bdaddr");
+               tester_test_failed();
+               return;
+       }
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_connect_cb(bthost, smp_client_new_conn, data);
+
+       bthost_hci_connect(bthost, master_bdaddr, BDADDR_LE_PUBLIC);
+}
+
+int main(int argc, char *argv[])
+{
+       tester_init(&argc, &argv);
+
+       test_smp("SMP Server - Basic Request 1",
+                                       &smp_server_basic_req_1_test,
+                                       setup_powered_server, test_server);
+       test_smp("SMP Server - Invalid Request 1",
+                                       &smp_server_nval_req_1_test,
+                                       setup_powered_server, test_server);
+       test_smp("SMP Server - Invalid Request 2",
+                                       &smp_server_nval_req_2_test,
+                                       setup_powered_server, test_server);
+
+       test_smp("SMP Client - Basic Request 1",
+                                       &smp_client_basic_req_1_test,
+                                       setup_powered_client, test_client);
+
+       return tester_run();
+}