+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.
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
include Makefile.tools
include Makefile.obexd
-include Makefile.android
+include android/Makefile.am
if HID2HCI
rulesdir = @UDEV_DIR@/rules.d
+++ /dev/null
-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
@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
@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 \
@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
"$(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
@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) \
@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) \
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 \
@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)
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) \
$(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) \
$(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) \
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 \
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)
@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 \
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
.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*) \
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
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)
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):
@$(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)
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) \
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)
@: > 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)
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) \
$(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)
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)
$(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)
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)
-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)
-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)
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@
@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@
@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@
@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
@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
-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)
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
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
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 \
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 \
# 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)
#
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)
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)
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+/*
+ *
+ * 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;
+ }
+}
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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 = ¶ms.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, ¶ms);
+}
+
+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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 = ¤t_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);
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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;
+}
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
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
Notifications parameters: State (1 octect)
+ Valid state values: 0x00 = Off
+ 0x01 = On
+
Opcode 0x82 - Adapter Properties Changed notification
Notification parameters: Status (1 octect)
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)
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)
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
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.
Opcode 0x81 - Connection State notification
Notification parameters: Remote address (6 octets)
+ Connection State (1 octets)
Valid connection states: 0x00 = Connected
0x01 = Connecting
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)
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:
--- /dev/null
+/*
+ * 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(¬if_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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ *
+ * 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));
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
+
+
--- /dev/null
+/*
+ * 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 */
+
+
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ *
+ * 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;
+ }
+}
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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);
#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);
}
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;
}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ *
+ * 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("");
+}
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ *
+ * 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();
+}
*
*/
-#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);
}
#! /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.
# 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=''
# 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]...
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
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.
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 $@
# Define the identity of the package.
PACKAGE='bluez'
- VERSION='5.10'
+ VERSION='5.11'
cat >>confdefs.h <<_ACEOF
# 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
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\\"
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])
boolean Deleted [writeonly]
- Message read flag
+ Message deleted flag
boolean Sent [readonly]
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;
};
l2conn_free(l2conn);
}
+ while (conn->cid_hooks) {
+ struct cid_hook *hook = conn->cid_hooks;
+
+ conn->cid_hooks = hook->next;
+ free(hook);
+ }
+
free(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)
&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;
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);
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);
if (data->removed != NULL)
emit_interfaces_removed(data);
+ data->process_id = 0;
+
return FALSE;
}
if (data->process_id > 0) {
g_source_remove(data->process_id);
+ data->process_id = 0;
process_changes(data);
}
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:
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;
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];
#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];
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;
}
#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), ' ', \
{ "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' },
{ }
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;
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" },
" 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));
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)
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;
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)
{
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;
}
}
}
+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)
{
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:
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;
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)
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;
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;
case 0x03:
str = "Allow Scan Request from White List Only, "
"Allow Connect Request from White List Only";
+ break;
default:
str = "Reserved";
break;
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)
{ 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 },
{ 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",
{ 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" },
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);
+ }
+}
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);
#include "obexd.h"
#include "server.h"
-#define DEFAULT_ROOT_PATH "/tmp"
-
#define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
static GMainLoop *main_loop = NULL;
"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,
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");
*/
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,
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);
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);
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);
}
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);
}
&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,
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;
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;
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)
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;
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);
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;
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;
}
/*
- * 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.
*/
}
/*
- * 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.
*/
}
/*
- * 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.
*/
}
/*
- * 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.
*/
}
/*
- * 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.
*/
}
/*
- * 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.
*/
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.
*/
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);
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]
#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>
#include "sdp-client.h"
#include "attrib/gatt.h"
#include "agent.h"
-#include "sdp-xml.h"
#include "storage.h"
#include "attrib-server.h"
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;
};
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);
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)
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;
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;
}
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;
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,
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,
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;
}
#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;
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) {
};
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,
};
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,
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)",
#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;
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; \
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)
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; \
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)
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; \
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)
}
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;
.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),
};
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),
};
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),
};
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),
.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),
};
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),
.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),
.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 };
.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),
};
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),
};
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),
};
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),
};
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),
.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),
};
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),
.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 };
};
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),
};
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),
.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),
};
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),
.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 };
};
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),
};
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),
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),
};
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),
};
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),
};
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,
.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 };
};
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),
};
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),
.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),
};
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),
};
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),
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),
};
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),
};
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),
};
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),
};
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),
};
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', ' ',
};
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),
};
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),
};
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),
};
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),
};
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),
};
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),
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),
};
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),
};
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),
};
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),
};
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),
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),
};
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),
};
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),
};
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),
.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)
{
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)
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)
{
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,
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)
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,
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",
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);
&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,
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);
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);
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);
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);
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,
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);
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);
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);
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);
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,
--- /dev/null
+/*
+ *
+ * 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();
+}