Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bc6fea3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+#
+#    Copyright (c) 2010-2011 Nest, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the makefile for BlueZ, the official Linux
+#      Bluetooth protocol stack.
+#
+
+
+include pre.mak
+
+PackageName		:= bluez
+
+PackageSourceDir	:= repo
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,Makefile)
+
+CleanPaths		+= $(PackageLicenseFile)
+
+SOURCEDIRS                      = $(PackageSourceDir)
+$(PackageSourceDir)_RULE_TARGET = $(BuildDirectory)/configure
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/LICENSE: $(BuildDirectory)/source
+
+$(PackageLicenseFile): $(PackageSourceDir)/LICENSE
+	$(copy-result)
+
+# Prepare the sources.
+
+.PHONY: source
+source: $(BuildDirectory)/source
+$(BuildDirectory)/source: | $(PackageSourceDir) $(BuildDirectory)
+	$(Verbose)$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+	$(Verbose)touch $@
+
+# Generate the package's build makefile
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: $(BuildDirectory)/configure
+$(BuildDirectory)/configure: $(BuildDirectory)/source | $(PackageSourceDir) $(BuildDirectory)
+	$(Verbose)cd $(BuildDirectory) && ./bootstrap
+	$(Verbose)cd $(BuildDirectory) && ./configure \
+	CC="$(CC) $(CPPOPTFLAGS)" CXX="$(CXX) $(CPPOPTFLAGS)" AR=$(AR) NM=$(NM) RANLIB=$(RANLIB) STRIP=$(STRIP) INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	CPPFLAGS="$(call ToolGenerateDefineArgument,FIRMWARE_DIR=\\\"/lib/firmware/\\\") \
+	          $(call ToolGenerateIncludeArgument,$(LinuxIncludePath))" \
+	DBUS_CFLAGS="$(call ToolGenerateIncludeArgument,$(DbusIncludePaths))" \
+	GLIB_CFLAGS="$(call ToolGenerateIncludeArgument,$(GlibIncludePaths))" \
+	UDEV_CFLAGS="$(call ToolGenerateIncludeArgument,$(UdevIncludePaths))" \
+	DBUS_LIBS="$(call GenerateLibraryArgument,$(DbusLibraryPath))" \
+	GLIB_LIBS="$(call GenerateLibraryArgument,$(GlibLibraryPath))" \
+	UDEV_LIBS="$(call GenerateLibraryArgument,$(UdevLibraryPath))" \
+	PKG_CONFIG_PATH="$(GlibPkgConfigPath):$(DbusPkgConfigPath):$(UdevPkgConfigPath)" \
+	--build=$(HostTuple) \
+	--host=$(TargetTuple) \
+	--prefix=/usr \
+	--sysconfdir=/etc \
+	--localstatedir=/var \
+	--disable-cups \
+	--disable-monitor \
+	--disable-client \
+	--disable-systemd \
+	--disable-obex \
+	$(if $(BUILD_FEATURE_BLUEZ_LIB), --enable-library) \
+	$(NULL)
+	$(Verbose)touch $@
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: build
+build: $(BuildDirectory)/build
+$(BuildDirectory)/build: $(BuildDirectory)/configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	all
+	$(Verbose)touch $@
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+$(BuildDirectory)/stage: $(BuildDirectory)/build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	DESTDIR=$(ResultDirectory) \
+	install
+	$(Verbose)touch $@
+
+stage: $(BuildDirectory)/stage
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/repo/.mailmap b/repo/.mailmap
new file mode 100644
index 0000000..a7e36e3
--- /dev/null
+++ b/repo/.mailmap
@@ -0,0 +1,11 @@
+Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>	<luiz.dentz-von@nokia.com>
+Vinicius Costa Gomes <vinicius.gomes@openbossa.org>	<vinicius.gomes@openbossa.org>
+Elvis Pfützenreuter <epx@signove.com>			<epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>		<scarot@libresoft.es>
+José Antonio Santos Cadenas <santoscadenas@gmail.com>	<santoscadenas@gmail.com>
+Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>	<Waldemar.Rymarkiewicz@tieto.com>
+Alok Barsode <alokbarsode@gmail.com>			<alok@greatbear.(none)>
+André Dieb Martins <andre.dieb@signove.com>		<andre.dieb@signove.com>
+Tedd Ho-Jeong An <tedd.an@intel.com>			<tedd.an@intel.com>
+Martin Xu <martin.xu@linux.intel.com>			<martin.xu@linux.intel.com>
+Marie Janssen <jamuraa@chromium.org>			<jamuraa@chromium.org>
diff --git a/repo/AUTHORS b/repo/AUTHORS
new file mode 100644
index 0000000..16fb14c
--- /dev/null
+++ b/repo/AUTHORS
@@ -0,0 +1,101 @@
+Maxim Krasnyansky <maxk@qualcomm.com>
+Marcel Holtmann <marcel@holtmann.org>
+Stephen Crane <steve.crane@rococosoft.com>
+Jean Tourrilhes <jt@hpl.hp.com>
+Jan Beutel <j.beutel@ieee.org>
+Ilguiz Latypov <ilatypov@superbt.com>
+Thomas Moser <thomas.moser@tmoser.ch>
+Nils Faerber <nils@kernelconcepts.de>
+Martin Leopold <martin@leopold.dk>
+Wolfgang Heidrich <wolfgang.heidrich@esk.fhg.de>
+Fabrizio Gennari <fabrizio.gennari@philips.com>
+Brad Midgley <bmidgley@xmission.com>
+Henryk Ploetz <henryk@ploetzli.ch>
+Philip Blundell <pb@nexus.co.uk>
+Johan Hedberg <johan.hedberg@intel.com>
+Claudio Takahasi <claudio.takahasi@indt.org.br>
+Eduardo Rocha <eduardo.rocha@indt.org.br>
+Denis Kenzior <denis.kenzior@trolltech.com>
+Frederic Dalleau <frederic.dalleau@access-company.com>
+Frederic Danis <frederic.danis@access-company.com>
+Luiz Augusto von Dentz <luiz.dentz@gmail.com>
+Fabien Chevalier <fabchevalier@free.fr>
+Ohad Ben-Cohen <ohad@bencohen.org>
+Daniel Gollub <dgollub@suse.de>
+Tom Patzig <tpatzig@suse.de>
+Kai Vehmanen <kai.vehmanen@nokia.com>
+Vinicius Gomes <vinicius.gomes@openbossa.org>
+Alok Barsode <alok.barsode@azingo.com>
+Bastien Nocera <hadess@hadess.net>
+Albert Huang <albert@csail.mit.edu>
+Glenn Durfee <gdurfee@google.com>
+David Woodhouse <david.woodhouse@intel.com>
+Christian Hoene <hoene@uni-tuebingen.de>
+Pekka Pessi <pekka.pessi@nokia.com>
+Siarhei Siamashka <siarhei.siamashka@nokia.com>
+Nick Pelly <npelly@google.com>
+Lennart Poettering <lennart@poettering.net>
+Gustavo Padovan <gustavo@padovan.org>
+Marc-Andre Lureau <marc-andre.lureau@nokia.com>
+Bea Lam <bea.lam@nokia.com>
+Zygo Blaxell <zygo.blaxell@xandros.com>
+Forrest Zhao <forrest.zhao@intel.com>
+Scott Talbot <psyc@stalbot.com>
+Ilya Rubtsov <lusyaru@gmail.com>
+Mario Limonciello <mario_limonciello@dell.com>
+Filippo Giunchedi <filippo@esaurito.net>
+Jaikumar Ganesh <jaikumar@google.com>
+Elvis Pfutzenreuter <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>
+José Antonio Santos Cadenas <jcaden@libresoft.es>
+Francisco Alecrim <francisco.alecrim@openbossa.org>
+Daniel Orstadius <daniel.orstadius@gmail.com>
+Anderson Briglia <anderson.briglia@openbossa.org>
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruna Moreira <bruna.moreira@openbossa.org>
+Brian Gix <bgix@codeaurora.org>
+Andre Guedes <andre.guedes@openbossa.org>
+Sheldon Demario <sheldon.demario@openbossa.org>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Szymon Janc <szymon.janc@codecoup.pl>
+Syam Sidhardhan <s.syam@samsung.com>
+Paulo Alcantara <pcacjr@gmail.com>
+Jefferson Delfes <jefferson.delfes@openbossa.org>
+Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+Eder Ruiz Maria <eder.ruiz@openbossa.org>
+Mikel Astiz <mikel.astiz@bmw-carit.de>
+Chan-yeol Park <chanyeol.park@samsung.com>
+João Paulo Rechi Vita <jprvita@gmail.com>
+Larry Junior <larry.junior@openbossa.org>
+Raymond Liu <raymond.liu@intel.com>
+Radoslaw Jablonski <ext-jablonski.radoslaw@nokia.com>
+Rafal Michalski <michalski.raf@gmail.com>
+Dmitriy Paliy <dmitriy.paliy@nokia.com>
+Bartosz Szatkowski <bulislaw@linux.com>
+Lukasz Pawlik <lucas.pawlik@gmail.com>
+Slawomir Bochenski <lkslawek@gmail.com>
+Wayne Lee <waynelee@qualcomm.com>
+Ricky Yuen <ryuen@qualcomm.com>
+Takashi Sasai <sasai@sm.sony.co.jp>
+Andre Dieb Martins <andre.dieb@signove.com>
+Cristian Rodríguez <crrodriguez@opensuse.org>
+Alex Deymo <deymo@chromium.org>
+Petri Gynther <pgynther@google.com>
+Scott James Remnant <scott@netsplit.com>
+Jakub Tyszkowski <jakub.tyszkowski@tieto.com>
+Grzegorz Kołodziejczyk <grzegorz.kolodziejczyk@tieto.com>
+Marcin Krąglak <marcin.kraglak@tieto.com>
+Łukasz Rymanowski <lukasz.rymanowski@codecoup.pl>
+Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
+Arman Uguray <armansito@chromium.org>
+Artem Rakhov <arakhov@chromium.org>
+Mike Ryan <mikeryan@lacklustre.net>
+David Herrmann <dh.herrmann@gmail.com>
+Jacob Siverskog <jacob@teenageengineering.com>
+Sebastian Chłąd <sebastian.chlad@tieto.com>
+Alex Gal <a.gal@miip.ca>
+Loic Poulain <loic.poulain@intel.com>
+Gowtham Anandha Babu <gowtham.ab@samsung.com>
+Bharat Panda <bharat.panda@samsung.com>
+Marie Janssen <jamuraa@chromium.org>
+Jaganath Kanakkassery <jaganath.k@samsung.com>
diff --git a/repo/COPYING b/repo/COPYING
new file mode 100644
index 0000000..6d45519
--- /dev/null
+++ b/repo/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/repo/COPYING.LIB b/repo/COPYING.LIB
new file mode 100644
index 0000000..1f7c8cc
--- /dev/null
+++ b/repo/COPYING.LIB
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/repo/ChangeLog b/repo/ChangeLog
new file mode 100644
index 0000000..c7a4fc0
--- /dev/null
+++ b/repo/ChangeLog
@@ -0,0 +1,2107 @@
+ver 5.37:
+	Fix issue with registering external profiles.
+	Fix issue with connecting external profiles.
+	Fix issue with GATT service changed handling.
+	Fix issue with not emitting GattServices update.
+	Convert to unified HID over GATT profile support.
+	Convert to KeyboardDisplay as default IO capability.
+	Install btattach utility by default.
+
+ver 5.36:
+	Fix issue with PBAP headers for size query.
+	Fix issue with AVRCP current player handling.
+	Fix issue with device information handling.
+	Fix issue with device disconnect handling.
+	Fix issue with duplicate connect handling.
+	Fix issue with attribute claiming for drivers.
+
+ver 5.35:
+	Fix issue with connected devices after discovery.
+	Fix issue with profile support and LTK loading.
+	Fix issue with AVRCP events for volume control.
+	Fix issue with OBEX session owner handling.
+	Fix issue with HID over GATT setup failures.
+	Fix issue with GATT notification registration.
+	Fix issue with GATT cache validation feature.
+	Add support for persistent GATT database.
+	Add support for controller enabling option.
+
+ver 5.34:
+	Fix issue with GATT profiles and auto-connect.
+	Fix issue with missing GoepL2CapPsm SDP data.
+	Fix issue with suspending AVDTP endpoints.
+	Fix issue with audio service state on disconnect.
+	Add support for AVRCP Set Addressed Player feature.
+	Add support for AVRCP Get Folder Items feature.
+	Add support for Android 5.1 HFP WBS callbacks.
+
+ver 5.33:
+	Fix issue with memory leak in GATT database.
+	Fix issue with AVDTP set configuration handling.
+	Fix issue with AVDTP discover procedure.
+	Fix issue with not emitting Paired property.
+
+ver 5.32:
+	Fix issue with OPP GET request path handling.
+	Fix issue with ATT information request errors.
+	Fix issue with advertising instance numbers.
+	Fix issue with overwriting SDP record cache.
+	Fix issue with new connections during disconnect.
+	Add support for GATT security auto-elevation.
+
+ver 5.31:
+	Fix issue with crash in networking interface.
+	Fix issue with crash when creating endless GATT loops.
+	Fix issue with memory leak when connecting services.
+	Fix issue with memory leak creating new D-Bus proxy.
+	Fix issue with profile connections from remote devices.
+	Fix issue with GATT over BR/EDR and MTU notification.
+	Fix issue with HID and dual mode remote devices.
+	Fix issue with handling A2DP vendor codec setup.
+	Fix issue with AVRCP and syncing player state.
+	Fix issue with GATT secondary discovery handling.
+	Fix issue with wrong characteristic allocation.
+	Add support for handling BNEP setup response.
+	Add support for setting GATT database security flags.
+	Add support for setting discovery filters interface.
+	Add support for user controlled advertising interface.
+	Update Android qualification documentation to PTS 6.1 release.
+
+ver 5.30:
+	Fix compilation error in C++ due to inline function.
+	Fix issue with missing storage of device information.
+	Fix issue with GATT client and gaps in service handles.
+	Fix issue with AVDTP discovery callback crashing.
+	Fix issue with AVCTP channel handling in case of conflicts.
+	Fix issue with AVRCP target and get capabilities command.
+	Add experimental support for LE advertising manager API.
+	Add support for Android 5.1 GATT MTU exchange API.
+
+ver 5.29:
+	Fix issue with AVCTP initial key repeat timeout.
+	Fix issue with Android application disconnect handling.
+	Fix issue with Android support and service notifications.
+	Fix issue with Android support and Exchange MTU Request.
+	Fix issue with Android HFP support and AT+CMER handling.
+	Fix issue with Android HFP support and SLC setup.
+	Fix issue with Android HFP support and call hold status.
+	Fix issue with Android HFP support and indicator handling.
+	Fix issue with Android HFP support and SCO/eSCO disconnection.
+	Fix issue with Android HID over GATT support and battery service.
+	Fix issue with GATT sending Exchange MTU Request for BR/EDR.
+	Fix issue with GATT notification support without CCC.
+	Fix issue with GATT object life-time after disconnects.
+	Fix issue with GATT notification handling API.
+	Add experimental support for GATT client D-Bus API.
+	Add experimental support for GATT server D-Bus API.
+	Add support for Multi Profile Specification.
+	Update Android qualification documentation to PTS 6.0 release.
+
+ver 5.28:
+	Fix issue with GATT device discovery and probing.
+	Fix issue with bearer selection for dual-mode devices.
+	Fix issue with device removal while connected.
+	Fix issue with device name setting from inquiry response.
+	Fix issue with missing termination of name characteristic.
+	Fix issue with UTF-8 length handling for device name.
+	Fix issue with AVCTP key auto release handling.
+	Fix issue with AVCTP key press repetition handling.
+	Fix issue with payload sizes and GATT notifications.
+	Fix issue with memory corruption and GATT notifications.
+	Add support for HID proxy switching and CSR 8510 A10 devices.
+	Add support for Broadcom hex2hcd conversion utility.
+
+ver 5.27:
+	Fix issue with endian handling and management interface.
+	Fix issue with pending GATT operations when disconnecting.
+	Fix issue with 128-bit UUID conversions for HID over GATT.
+	Add support for Android 5.0 SELinux policies.
+
+ver 5.26:
+	Fix issue with handling A2DP XCASE connection state.
+	Fix issue with crash and A2DP configuration failures.
+	Fix issue with crash during OBEX session shutdown.
+	Add support for version 1.2 of Phonebook Access Profile.
+	Add support for HID over GATT get and set report handling.
+	Add support for Low Energy Secure Connections feature.
+	Add support for Bluetooth 4.2 commands and events.
+	Add support for Android 5.0 Bluetooth features.
+
+ver 5.25:
+	Fix issue with SCO connection after codec negotiation.
+	Fix issue with GATT and secondary service discovery.
+	Fix issue with GATT write descriptor callback.
+	Fix issue with MAP supported features bits.
+	Add support for MAP local time and timezone offset.
+	Add support for PBAP speed-dial and favorites folders.
+	Add support for PBAP speed-dial and identifier filters.
+	Add support for controller mode configuration option.
+	Add initial support for Android Lollipop features.
+
+ver 5.24:
+	Fix issue with storing of connection parameters.
+	Add support for Phonebook Access Profile 1.2 features.
+	Add support for Message Access Profile 1.2 event reports.
+	Add support for Android Bluetooth configuration options.
+
+ver 5.23:
+	Fix issue with concurrent authorization requests.
+	Fix issue with HID report identifier mismatch.
+	Fix issue with crash when receiving uHID events.
+	Fix issue with crash and OBEX disconnect handling.
+	Fix issue with OBEX client transfers and suspend.
+	Fix issue with parsing of MAP application parameters.
+	Fix issue with devices rejecting AVRCP GetCapabilities.
+	Add support for kernel whitelist and Android Bluetooth.
+
+ver 5.22:
+	Fix issue with UHID_OUTPUT events mapping.
+	Fix issue with UHID_FEATURE events handling.
+	Fix issue with UINT32_MAX overflow and AVRCP.
+	Fix issue when dirent type DT_UNKNOWN is returned.
+	Add support for kernel whitelist filtering feature.
+	Add support for Android Bluetooth GATT over BR/EDR.
+
+ver 5.21:
+	Fix issue with SDP requests and wrong PDU size.
+	Fix issue with handling passive scanning triggers.
+	Add support for storing and loading connection parameters.
+	Add support for kernel background auto-connection feature.
+	Add support for Android Bluetooth Scan Parameters feature.
+	Add support for Android Bluetooth Device Information feature.
+	Add support for Android Bluetooth Health Device interface.
+
+ver 5.20:
+	Fix issue with LED handling of PS3 controllers.
+	Add support for Android Bluetooth GATT server interface.
+	Add support for Android Bluetooth HID over GATT feature.
+	Add support for Android Bluetooth multi-profile feature.
+	Add support for Android Bluetooth aptX audio integration.
+
+	Note: aptX codec not included
+
+ver 5.19:
+	Fix issue with OBEX Put-Delete and Create-Empty methods.
+	Fix issue with AVRCP browsable/searchable player properties.
+	Fix issue with handling multiple default agents.
+	Fix issue with handling unpair event per bearer.
+	Fix issue with HID over GATT report ID presence.
+	Add support for HID protocol handling in userspace.
+	Add support for Bluetooth reconnection policy framework.
+	Add support for Android Bluetooth SCO over HCI transport.
+	Add support for Android Bluetooth audio quality control.
+	Add support for Android Bluetooth Low Energy only mode.
+
+ver 5.18:
+	Fix issue with identifying LE single mode devices.
+	Fix issue with L2CAP and RFCOMM peer address lookup.
+	Add support for handling OBEX authentication procedure.
+	Add support for Android Bluetooth GATT client interface.
+
+ver 5.17:
+	Fix issue with not resetting OBEX SRM setup.
+	Fix issue with BR/EDR devices and auto-connect list.
+	Fix issue with bonding complete detection as peripheral.
+	Fix issue with not updating bearer timestamp of connections.
+	Fix issue with paired property for multiple bearers.
+	Add support for Android Bluetooth Handsfree interface.
+	Add support for Android Bluetooth Wideband speech.
+
+ver 5.16:
+	Fix issue with HID over GATT physical location.
+	Fix issue with HID over GATT unique identifier.
+	Fix issue with missing paired property notification.
+	Fix issue with endianess of long term key storage.
+	Add support for storing signature resolving keys.
+	Add support for Android Bluetooth AVRCP interface.
+
+ver 5.15:
+	Fix issue with LE enabling and background scanning.
+	Fix issue with HID over GATT input device name.
+	Fix issue with storage of slave long term keys.
+	Add support for handling identity resolving keys.
+	Add support for Android Bluetooth A2DP interface.
+	Add support for Android Bluetooth audio interface.
+
+ver 5.14:
+	Fix issue with marking PS3 controllers as trusted.
+	Fix issue with authorization of PS3 controllers.
+	Add support for DualShock 4 controller detection.
+	Add support for legacy pairing emulation.
+	Add support for secure simple pairing emulation.
+	Add support for automated pairing testing.
+	Add support for RFCOMM protocol testing.
+	Add support for HCI controller testing.
+
+ver 5.13:
+	Fix issue with PS3 controller detection.
+	Add support for data transfers to L2CAP testing tool.
+	Add support for delay reporting to AVDTP testing tool.
+	Add support for Android Bluetooth Core interface.
+	Add support for Android Bluetooth Socket interface.
+	Add support for Android Bluetooth HID Host interface.
+	Add support for Android Bluetooth PAN interface.
+
+ver 5.12:
+	Fix issue with missing reply to DisconnectProfile.
+	Fix issue with icon property and class of device changes.
+	Fix issue with HID devices when SDP record is not available.
+	Fix issue with handling auto-pairing of printers.
+	Fix issue with agent authorization handling.
+	Add support for PS3 controller setup and pairing.
+	Add support for LE L2CAP CoC test capabilities.
+	Add support for AVDTP qualification test cases.
+	Add support for SMP cryptographic test cases.
+
+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.
+	Fix issue with MAP messages and status events.
+	Fix issue with MAP messages and relative folders.
+	Fix issue with MAP messages and type property signals.
+	Fix issue with transfer size for OBEX GET operations.
+	Fix issue with AVRCP service class identifier.
+	Fix issue with AVRCP tracking seeked signal.
+	Add support for OBEX command line client.
+
+ver 5.9:
+	Fix issue with network service and adapter removal.
+	Fix issue with misleading OBEX error messages.
+	Fix issue with OBEX transport reference handling.
+	Fix issue with memory leak with MAP event handler.
+	Fix issue with missing MAP property changed signal.
+	Fix issue with message type property values.
+	Fix issue with empty UUID list for devices.
+	Fix issue with profile agent cancel method.
+	Remove dependency on USB library.
+
+ver 5.8:
+	Fix issue with missing OBEX session properties.
+	Fix issue with missing SDP service refresh.
+	Fix issue with SDP attribute range check.
+	Fix issue with priority for SDP transactions.
+	Fix issue with service discovery after pairing.
+	Fix issue with race condition in service list.
+	Fix issue with input service state transition.
+	Fix issue with default authorization for profiles.
+	Fix issue with AVRCP browsing channel connections.
+	Add support for AVRCP role agnostic sessions.
+
+ver 5.7:
+	Fix issue with missing UUID discovery during pairing.
+	Fix issue with broken patch for SDP range check handling.
+	Fix issue with AVRCP usage of UID=0 for paused/stopped.
+	Add support MAP notification dispatching.
+
+ver 5.6:
+	Fix issue with incoming connections without SDP record.
+	Fix issue with canceling ongoing device connections.
+	Fix issue with handling failed connection attempts.
+	Fix issue with pending resume during A2DP open failures.
+	Fix issue with registering AVRCP unsupported notification.
+	Fix issue with listing available AVRCP target settings.
+	Fix issue with missing error for OBEX SetPath commands.
+	Fix issue with missing OBEX session command queue.
+	Fix issue with retrieving multiple MAP event reports.
+	Add support for command line player utility.
+
+ver 5.5:
+	Fix issue with race condition between SDP and properties.
+	Fix issue with handling storage of private device addresses.
+	Fix issue with NFC out-of-band pairing and power states.
+	Fix issue with short name during device update handling.
+	Fix issue with handling AVRCP without A2DP being present.
+	Add support for handling AVRCP pass-through operations.
+	Add support for automatically reconnecting HID devices.
+	Add support for automatically pairing of devices.
+
+ver 5.4:
+	Fix issue with invalid memory access and SDP service search.
+	Add support for available player changed event for controller.
+	Add support for UIDs changed event for AVRCP controller.
+	Add support for mandatory AVRCP pass-through operations.
+	Add support for Message Notification Service (MNS) server.
+	Add support for agent methods within command line client.
+
+ver 5.3:
+	Fix issue with registering invalid profiles.
+	Fix issue with inconsistent A2DP transport state.
+	Fix issue with A2DP resume while in configured state.
+	Fix issue with buffer overflow when processing SDP response.
+	Fix issue with missing range check for SDP attribute response.
+	Fix issue with missing validation of SDP data elements.
+	Fix issue with missing fallback to static hostname.
+	Fix issue with default adapter assignment.
+
+ver 5.2:
+	Fix issue with connection handling for Low Energy.
+	Fix issue with broken device discovery handling.
+	Fix issue with invalid memory access within A2DP.
+	Fix issue with handling empty path name of SetPath.
+	Fix issue with handling Message Access Profile filters.
+	Fix issue with handling network service unregistration.
+	Fix issue with not handling bogus device pairing results.
+	Fix issue with initial service discovery and profile manager.
+	Add support for AVRCP volume notifications.
+	Add support for AVRCP browsing commands.
+
+ver 5.1:
+	Fix issue with crash when removing OBEX session.
+	Fix issue with HID device disconnected from kernel.
+	Fix issue with buffer overflow when parsing HID SDP record.
+	Fix issue with SDP_TEXT_STR16 and SDP_URL_STR16 parsing.
+	Add support for integration with systemd's hostname daemon.
+	Add support for separate adapter alias property.
+	Add support for adapter and device modalias properties.
+	Add support for official BlueZ device information.
+	Add support for asynchronous management interface handling.
+	Add tool for testing management interface compliance.
+	Add tool for testing SDP qualification requirements.
+	Add tool for testing various EIR and AD data records.
+
+ver 5.0:
+	Introduce D-Bus Properties and ObjectManager interfaces.
+	Add support for generic profile interface.
+	Add support for global agent interface.
+	Add support for integrated OBEX daemon.
+	Add support for integrated hcidump utility.
+	Add support for Bluetooth tracing and monitor utility.
+	Add support for Bluetooth command line client utility.
+	Remove support for Handsfree gateway handling.
+	Remove support for GStreamer A2DP and SBC elements.
+	Disable default installation of Bluetooth library.
+
+ver 4.101:
+	Fix issue with missing BlueZ service file.
+	Fix issue with aborting A2DP setup during AVDTP start.
+	Fix issue with handling of multiple A2DP indication.
+	Fix issue with handling AVDTP abort with invalid SEID.
+	Fix issue with rejecting AVDTP abort commands.
+	Add support for handling AVDTP command collision.
+
+ver 4.100:
+	Fix issue with crashing when SCO connection fails.
+	Fix issue with HFP gateway failing on first GSM connection.
+	Fix issue with AVRCP and handling of vendor commands.
+	Fix issue with handling AVRCP subunit info command.
+	Fix issue with missing capability for AVRCP track reached end.
+	Fix issue with AVDTP signaling and GStreamer SBC NULL check.
+	Fix issue with AVDTP Reconfigure Reject message.
+	Fix issue with incorrect EIR length parsing.
+	Fix issue with SDP disconnect for HIDSDPDisable.
+	Fix issue with SDP interoperability with Mac OS X Lion.
+	Fix issue with reverse SDP discovery with some devices.
+	Fix issue with discovering state during power off operation.
+	Add support for AVRCP Volume Changed notifications.
+	Add support for AVRCP Set Absolute Volume handling.
+	Add support for display legacy PIN code agent method.
+	Add support for multiple media transports per endpoint.
+	Add support for discovering device information characteristics.
+	Add support for vendor source for Device ID setting.
+	Add support for immediate alert server.
+	Add support for link loss server.
+
+	Notes:
+	This version requires D-Bus 1.4 or later.
+	This version requires GLib 2.28 or later.
+
+ver 4.99:
+	Fix issue with missing retries for BNEP connection setup.
+	Fix issue with not showing name if first EIR has no details.
+	Fix issue with running SDP discovery for LE devices.
+	Add support for GATT using 128-bit Bluetooth UUIDs.
+	Add support for retrieving key size information.
+	Add support for storing Long Term Keys.
+	Add support for Proximity Reporter API.
+	Add support for KeyboardDisplay IO capability.
+	Add support for version 1.0 of management API.
+	Add support for monitoring interface.
+
+ver 4.98:
+	Fix issue with adapter list upon initialization failure.
+	Fix issue with missing legacy property for Low Energy.
+	Fix issue with missing EIR information handling.
+	Fix issue with device address type tracking.
+	Fix issue with alert level characteristic.
+	Fix issue with headset shutdown handling.
+	Fix issue with Wiimote address handling.
+	Add support for advanced l2test options.
+	Add support for attribute protocol and multiple adapters.
+
+ver 4.97:
+	Update support for proximity profile.
+	Fix issue with SBC audio decoding quality.
+	Fix multiple issues with HFP support.
+	Fix multiple issues with A2DP support.
+	Fix multiple issues with AVDTP support.
+	Fix multiple issues with AVRCP support.
+	Add support for AVRCP meta-data transfer.
+	Add support for Bluetooth based thermometers.
+
+ver 4.96:
+	Fix issue with race condition in AVDTP stream start.
+	Fix issue with global adapter offline switching.
+	Fix issue with pairing and No Bonding devices.
+	Add support for Nintendo Wii Remote pairing.
+
+ver 4.95:
+	Fix issue with AVCTP replies with invalid PID.
+	Fix issue with AVRCP and unknown packet types.
+	Fix issue with AVRCP not using NOT_IMPLEMENTED correctly.
+	Fix issue with AVDTP discovery if all endpoints are in use.
+	Fix issue with invalid memory writes and media support.
+	Fix issue with not removing device alias and unbonding.
+	Fix issue with device disconnects and offline mode handling.
+	Add support for setting adapter name based on machine-info.
+	Add support for systemd service configuration.
+
+ver 4.94:
+	Fix issue with invalid read of memory in various modules.
+	Fix issue with buffer overflow when sending AVDTP commands.
+	Fix issue with response to vendor dependent AVRCP commands.
+	Fix issue with headset when not able to reply with ERROR.
+	Fix issue with crash when creating a device from storage.
+	Fix issue with handling non UTF-8 devices names.
+	Add support for improved discovery procedure.
+
+ver 4.93:
+	Fix issue with property type and Health Main channel.
+	Fix issue with crash when removing devices.
+	Add support for hid2hci and udev integration.
+
+ver 4.92:
+	Fix issue with handling of A2DP suspend response.
+	Fix issue with crashing when acquiring A2DP stream.
+	Fix issue with missing check for valid SCO before shutdown.
+	Fix issue with waiting for POLLERR when disconnecting SCO.
+	Fix issue with disconnect after primary service discovery.
+	Fix issue with attribute interface registration.
+	Add support for primary services over BR/EDR.
+	Add support for flushable packets of A2DP media.
+
+ver 4.91:
+	Fix issue with LMP version string and hciconfig.
+	Fix issue with missing discovery signal when scanning.
+	Fix issue with wrong state and canceling name resolving.
+	Fix issue with missing check during adapter initialization.
+	Fix issue with missing protocol not supported error and A2DP.
+	Fix issue with crash during driver unregistering and A2DP.
+	Fix issue with crash when receiving AVDTP close command.
+	Fix issue with remote SEP handling when A2DP codec changes.
+	Fix issue with SCO hangup handling and state changes.
+	Fix issue with security level and MCAP instances.
+	Fix issue with memory leak and HDP data channels.
+	Add support for discover characteristics by UUID to gatttool.
+	Add initial support for Out-of-Band association model.
+	Add initial support for SIM Access Profile.
+
+ver 4.90:
+	Fix issue with setting of global mode property.
+	Fix issue with handling of RequestSession responses.
+	Fix issue with TP_BNEP_CTRL_BV_01_C qualification test.
+	Fix issue with too short AVDTP request timeout.
+	Add support for SIM Access Profile manager.
+	Add support for new UUID utility functions.
+	Add support for attribute server notifications.
+	Add support for client characteristic configuration.
+	Update support for interactive GATT utility.
+
+ver 4.89:
+	Fix issue with name resolving when discovery is suspended.
+	Fix issue with parsing flags of advertising report.
+	Fix issue with SEP handling if interface is disabled.
+	Fix issue with device object creation on disconnect event.
+	Fix issue with indicators whenever the driver is initialized.
+	Fix issue with call indicator when parsing call info reply.
+	Fix issue with crash and allowed GATT MTU was too large.
+	Add support for SDP record of Primary GATT services.
+	Add support for interactive mode for GATT utility.
+
+ver 4.88:
+	Fix issue with HID channel reference count handling.
+	Fix issue with daemon exit on badly formatted AT+VTS.
+	Fix issue with crash while parsing of endpoint properties.
+	Fix issue with possible crash on AVDTP Suspend request timeout.
+	Fix issue with stopping inquiry before adapter is initialized.
+	Fix issue with creating device object when connection fails.
+	Fix issue with sending HCIDEVUP when adapter is already up.
+	Fix issue with handling bonding IO channel closing.
+	Fix agent cancellation in security mode 3 situations.
+	Update pairing code to support management interface.
+
+ver 4.87:
+	Fix issue with initialization when adapter is already up.
+	Fix issue with attribute server MTU and incoming connections.
+	Fix issue with duplicate characteristics after discovery.
+
+ver 4.86:
+	Revert wrong fix for SDP PDU size error response.
+	Fix various memory leaks in A2DP and AVDTP support.
+	Add Routing property to MediaTransport interface
+	Add proper tracking mechanism to NREC status.
+	Add READ_BLOB_REQUEST support to attribute server.
+
+ver 4.85:
+	Fix issue with event mask setting for older adapters.
+	Fix issue with device creation and pairing failures.
+	Add support for telephony support via oFono.
+	Add support for characteristic security level.
+	Update support for service registration.
+
+ver 4.84:
+	Fix issue with wrong parameters and device found signals.
+	Fix issue with leaking EIR data if RSSI does not change.
+	Fix issue with adapter initialization state.
+	Fix issue with closing of SDP server sockets.
+
+ver 4.83:
+	Fix issue with already connected HFP/HSP endpoints.
+	Fix missing reply when create device is canceled.
+	Fix memory leak within the attribute server.
+	Fix memory leak with unused extended inquiry name.
+	Fix setting paired state when device->authr is false.
+	Fix clearing authentication request for renewed keys.
+	Add support for storing link keys in runtime memory.
+	Update support for primary service discovery.
+
+ver 4.82:
+	Fix crash with mmap of files with multiples of page size.
+	Fix HFP response and hold (AT+BTRH) command response.
+	Fix device creation error response when powered off.
+	Fix device removal when connecting/browsing fails.
+	Add initial attribute permission implementation.
+	Add AVDTP SRC stream send buffer size verification.
+	Add support for setting link policy based on features.
+
+ver 4.81:
+	Fix issue with telephony driver initialization.
+	Fix issue with adapter services list initialization.
+	Fix crash after simultaneous authentication requests.
+	Add support for primary service search on device creation.
+
+ver 4.80:
+	Fix legacy link key storing for some buggy adapters.
+	Fix invalid memory access when EIR field length is zero.
+	Fix adapter initialization to wait for kernel HCI commands.
+	Fix initialization of adapters which are already up.
+	Fix possible race condition when initializing adapters.
+	Fix possible crashes when attempting to connect AVDTP.
+	Fix not aborting sink stream configuration on disconnect.
+	Fix not indicating disconnected state when connecting to AVDTP.
+	Fix not dropping AVDTP session when canceling stream setup.
+	Fix AVDTP abort not being send when the state is idle.
+	Fix regression with Low Energy and interleave discovery.
+	Add a new configuration option to disable Low Energy support.
+	Add iwmmxt optimization for SBC for ARM PXA series CPUs.
+	Update support for GATT Primary Service Discovery.
+	Update MCAP and HDP support.
+
+ver 4.79:
+	Fix issue with adapter initialization race condition.
+	Update new Bluetooth Management interface support.
+
+ver 4.78:
+	Fix various issues with AVDTP timer handling.
+	Fix various issues with handling of mode changes.
+	Fix issue with audio disconnect watch in connecting state.
+	Fix issue with handling call waiting indicators in telephony.
+	Fix issue with handling UUID parameter and RegisterEndpoint.
+	Add initial support for Bluetooth Management interface.
+	Add support for Application property to HealthChannel.
+
+ver 4.77:
+	Fix issue with device name and accessing already freed memory.
+	Fix issue with handling CHLD=0 command for handsfree.
+	Fix issue with manager properties and no adapters.
+	Fix issue with properties and broken service records.
+	Fix issue with A2DP playback and sample rate changes.
+	Update MCAP and HDP support.
+
+ver 4.76:
+	Fix issue in telephony driver with hanging up held call.
+	Fix issue in telephony driver with notifications when on hold.
+	Fix issue with blocking on setconf confirmation callback.
+	Fix issue with not always signaling new streams as sinks.
+	Fix issue with errors in case of endpoint request timeout.
+	Fix issue with HFP/HSP microphone and speaker gain values.
+	Add source if the device attempt to configure local sink stream.
+	Add PSM option for GATT/ATT over BR/EDR on gatttool.
+	Add support for GATT/ATT Attribute Write Request.
+	Update MCAP and HDP support.
+
+ver 4.75:
+	Fix use of uninitialized variable on legacy pairing.
+	Fix mismatch of attribute protocol opcode.
+
+ver 4.74:
+	Fix regression for Legacy Pairing.
+	Fix wrong PSM value for attribute protocol.
+	Fix issue with RSSI field in advertising reports.
+	Add support for Add BR/EDR and LE interleaved discovery.
+	Add support for GATT write characteristic value option.
+	Add support for specifying download address for AR300x.
+
+ver 4.73:
+	Fix problem with EIR data when setting the name.
+	Fix reading local name from command complete event.
+	Fix registering local endpoints with disabled socket interface.
+	Add support for more HCI operations using ops infrastructure.
+	Add support for GATT characteristic hierarchy.
+	Add support for GATT indications.
+
+ver 4.72:
+	Fix memory leak while connecting BTIO channels.
+	Fix crash with GStreamer plugin if SBC is not supported.
+	Fix issue with GATT server stop sending notifications.
+	Fix issue with GATT and dealing with the minimum MTU size.
+	Fix issue with file descriptor leak in GATT client.
+	Add support for UUID 128-bit handling in attribute client.
+	Add support for encoders/decoders for MTU Exchange.
+	Add support for the MTU Exchange procedure to the server.
+	Add support for a per channel MTU to the ATT server.
+	Add support for Characteristic interface.
+	Add support for new Media API and framework.
+	Add initial support for HDP plugin.
+
+ver 4.71:
+	Fix compilation when SBC support in not enabled.
+	Fix crash with RequestSession and application disconnects.
+	Fix memory leak and possible crash when removing audio device.
+	Fix issue with closing stream of locked sep when reconfiguring.
+	Fix issue where discovery could interfere with bonding.
+	Fix issue with Connected status when PS3 BD remote connects.
+	Fix issue with lifetime of fake input devices.
+	Add support for compile time option of oui.txt path.
+	Add support for printing IEEE1284 device ID for CUPS.
+	Add plugin for setting adapter class via DMI.
+	Add more features for attribute protocol and profile.
+	Add initial support for MCAP.
+
+ver 4.70:
+	Fix incoming call indication handling when in WAITING state.
+	Fix various SDP related qualification test case issues.
+	Fix logic to write EIR when SDP records are changed.
+	Fix UTF-8 validity check for remote names in EIR.
+	Add support for UUID-128 extended inquiry response.
+	Add service UUIDs from EIR to the DeviceFound signal.
+	Add fast connectable feature for Handsfree profile.
+	Add HCI command and event definitions for AMP support.
+	Add firmware download support for Qualcommh devices.
+	Add host level support for Atheros AR300x device.
+	Add initial support of ATT and GATT for basic rate.
+
+ver 4.69:
+	Fix issue with calling g_option_context_free() twice.
+	Fix inconsistencies with initial LE commands and events.
+	Add support for telephony ClearLastNumber method.
+	Add support for network server interface.
+
+ver 4.68:
+	Fix initialization of adapters in RAW mode.
+	Fix signal strength for HFP in Maemo's telephony support.
+	Add support for following the radio state via Maemo's MCE.
+	Add initial set of LE commands and events definitions.
+	Add mode option for L2CAP sockets to the BtIO API.
+
+ver 4.67:
+	Fix issue with authentication reply when bonding already completed.
+	Fix issue with not canceling authentication when bonding fails.
+	Fix issue with changed combination keys and temporary storage.
+	Fix issue with sdp_get_supp_feat library function.
+	Fix issue with missing unblock on device removal.
+	Fix issue with not waiting for mode change completion.
+	Add ARMv6 optimized version of analysis filter for SBC encoder.
+
+ver 4.66:
+	Fix regression with full debug enabling via SIGUSR2.
+	Fix redundant speaker/microphone gains being sent.
+	Fix not emitting PropertyChanged for SpeakerGain/MicrophoneGain.
+	Fix issue with storage usage when a record is not found in memory.
+	Fix issue with DiscoverServices not retrieving any records.
+	Fix audio profile disconnection order to match whitepaper.
+	Fix auto-accept confirmation when local agent has NoInputNoOutput.
+	Fix remote just-works SSP when MITM protection is required.
+	Fix performing dedicated bonding without MITM requirement.
+	Add support for storing debug link keys in runtime memory.
+
+ver 4.65:
+	Fix issues with general bonding being default setting now.
+	Fix driver removal upon device removal.
+	Add new "Blocked" property to device objects.
+	Add hciconfig support for blacklisting.
+	Add support for dynamic debug feature.
+
+ver 4.64:
+	Fix invalid memory access in headset_get_nrec function.
+	Fix issue with disconnect event on higher protocol layers.
+	Fix issue with list parsing in sdp_set_supp_features function.
+	Fix device object reference counting for SDP browse requests.
+	Add missing memory checks whenever memory is allocated for SDP.
+	Add support for exporting local services via D-Bus.
+	Add more L2CAP Enhanced Retransmission test options.
+
+ver 4.63:
+	Fix avdtp_abort not canceling pending requests.
+	Fix stale connection when abort gets rejected.
+
+ver 4.62:
+	Fix accidental symbol breakage with inquiry transmit power.
+	Fix using invalid data from previous headset connection.
+	Fix double free on AVDTP Abort response.
+	Fix possible crash while verifying AVDTP version.
+	Fix missing inuse flag when AVDTP stream is configured.
+	Add support for Bluetooth controller types.
+
+ver 4.61:
+	Fix issues with Read Inquiry Response Transmit Power Level.
+	Fix possible invalid read when removing a temporary device.
+	Fix mode restoration when remember_powered is false.
+	Fix conference call releasing in telephony-maemo.
+	Fix segmentation fault with authorization during headset disconnects.
+	Add support for handling unanswered AVDTP request on disconnect.
+	Add support for handling Inquiry Response Transmit Power Level.
+	Add support for caching of remote host features.
+	Add preliminary voice dialing support for HSP.
+
+ver 4.60:
+	Fix voice mailbox number reading from SIM.
+	Fix some races with D-Bus mainloop integration.
+	Add helpers for D-Bus signal watches.
+
+ver 4.59:
+	Add values for Bluetooth 4.0 specification.
+	Add SDP functions for HDP support.
+	Add test scripts for input and audio.
+	Fix missing close on BtIO create_io function.
+	Fix sending incorrect AVDTP commands after timeout occurs.
+	Fix timer removal when device disconnects unexpectedly.
+	Fix Extended Inquiry Response record for Device ID.
+
+ver 4.58:
+	Fix crash when adapter agent exists during authentication.
+	Fix CK-20W quirks for play and pause events.
+
+ver 4.57:
+	Fix unloading of drivers for uninitialized adapters.
+	Fix debug message to use requested and not opened SEID.
+	Fix codec selection for GStreamer plugin.
+	Fix deleting of SDP records during service updates.
+	Fix deleting of SDP records when a device is removed.
+	Fix handling when the SDP record is modified on remote device.
+	Fix potential buffer overflow by using snprintf instead of sprintf.
+	Fix const declarations for some storage function parameters.
+
+ver 4.56:
+	Add missing values from Bluetooth 3.0 specification.
+	Add proper tracking of device paired status.
+	Fix tracking of devices without permanently stored link key.
+	Fix issue with link key removal after connection failures.
+	Fix legacy pairing information based on remote host features.
+	Fix off-by-one issue with AVDTP capability parsing.
+	Fix AVRCP, AVCTP, AVDTP, A2DP and HFP version numbers.
+	Fix agent canceling before calling agent_destroy.
+	Fix service record parsing with an empty UUID list.
+	Fix various SDP related memory leaks.
+
+ver 4.55:
+	Add support for POSIX capabilities dropping.
+	Add special quirk for the Nokia CK-20W car kit.
+	Fix error code handling for AVDTP SetConfiguration response.
+	Fix updating out of range list when RSSI hasn't changed.
+	Fix various memory leaks and unnecessary error checks.
+
+ver 4.54:
+	Add introspection interface to output of introspection calls.
+	Fix stream handling when media transport disconnects prematurely.
+	Fix command timeout handling when there's no stream.
+	Fix headset_suspend_stream behavior for invalid states
+	Fix issue with AVDTP ABORTING state transition.
+	Fix issue with AVDTP suspend while closing.
+
+ver 4.53:
+	Fix issue with telephony connection state notifications.
+	Fix AVDTP stream leak for invalid media transport config.
+	Fix audio connection authorization handling with timeouts.
+	Fix race condition in authorizing audio connections.
+	Fix device authorized setting for AVRCP-only connections.
+	Fix duplicate attempts from device to connect signal channel.
+
+ver 4.52:
+	Add AVCTP support to test utility.
+	Fix AVDTP Abort when transport closes before response.
+	Fix authorization when the audio profiles are slow to connect.
+	Fix potential AVDTP reference leaks.
+
+ver 4.51:
+	Add utility for basic AVDTP testing.
+	Add support for configuring L2CAP FCS option.
+	Fix discovery mode for CUPS 1.4.x and later.
+	Fix global state tracking of audio service.
+	Fix last issues with the new build system.
+
+ver 4.50:
+	Fix issue with missing manual pages in distribution.
+	Fix issue with the configuration and state directories.
+	Fix issue with creating include directory.
+	Fix dependencies of include file generation.
+
+ver 4.49:
+	Add simple test program for basic GAP testing.
+	Add support for confirmation requests to agent example.
+	Add support for full non-recursive build.
+	Add five millisecond delay for Simple Pairing auto-accept.
+	Fix Class of Device setting when InitiallyPowered=false.
+
+ver 4.48:
+	Add library function for comparing UUID values.
+	Add support for creating all plugins as builtins.
+	Add support for async handling of service class changes.
+	Add support for source interface to audio IPC.
+	Fix device name settings when device is off or down.
+	Fix issue with enabled SCO server when not necessary.
+	Fix missing D-Bus access policy for CUPS backend.
+	Fix discovery results of CUPS backend.
+	Fix initialization handling of Maemo telephony.
+
+ver 4.47:
+	Add support for RFKILL unblock handling.
+	Add support for serial proxy configurations.
+	Add support for caching service class updates.
+	Fix issues with updating SDP service records.
+	Fix usage of limited discoverable mode.
+	Remove deprecated methods and signals for AudioSource.
+
+ver 4.46:
+	Add support for A2DP sink role.
+	Fix clearing svc_cache before the adapter is up.
+	Fix various pointer after free usages.
+	Fix various memory leaks.
+
+ver 4.45:
+	Fix UDEV_DATADIR fallback if pkg-config fails.
+	Fix adapter cleanup and setup prototypes.
+	Fix double-free with out-of-range devices.
+	Fix inband ring setting to be per-headset.
+	Fix handling of Maemo CSD startup.
+
+ver 4.44:
+	Add some missing manual pages.
+	Fix missing number prefix when installing udev rules.
+	Fix program prefix used in Bluetooth udev rules.
+	Fix three-way calling indicator order.
+	Fix downgrade/upgrade of callheld indicator.
+	Fix +CIEV sending when indicator value changes.
+	Fix signal handling for Maemo telephony driver.
+	Fix parsing issues with messages from Maemo CSD.
+	Fix issue with duplicate active calls.
+
+ver 4.43:
+	Add support for udev based on-demand startup.
+	Fix verbose error reporting of CUPS backend.
+	Fix various string length issues.
+	Fix issues with Maemo telephony driver.
+	Fix another device setup and temporary flag issue.
+	Fix and update example agent implementation.
+
+ver 4.42:
+	Add TI WL1271 to Texas Instruments chip list.
+	Add special udev mode to bluetoothd.
+	Fix regression when there is no agent registered.
+	Fix error return when bonding socket hang up.
+	Fix SCO server socket for HFP handsfree role.
+	Fix shutdown on SCO socket before closing.
+	Fix shutdown on A2DP audio stream channel before closing.
+	Fix issue with asserting on AVDTP reference count bugs.
+	Fix authorization denied issue with certain headsets.
+	Fix AVRCP UNITINFO and SUBUNIT INFO responses.
+	Fix discovery cancel issues in case SDP discovery fails.
+
+ver 4.41:
+	Fix pairing even if the ACL gets dropped before successful SDP.
+	Fix regression which caused device to be removed after pairing.
+	Fix HSP record fetching when remote device doesn't support it.
+	Fix SDP discovery canceling when clearing hs->pending.
+	Fix headset never connecting on the first attempt.
+	Fix headset state tracking if bt_search_service() fails.
+	Fix maximum headset connection count check.
+	Fix AVDTP Discover timeout handling.
+	Fix also UI_SET_KEYBIT for the new pause and play key codes.
+
+ver 4.40:
+	Add telephony driver for oFono telephony stack.
+	Add support for Dell specific HID proxy switching.
+	Add support for running hid2hci from udev.
+	Add mapping for AVRCP Play and Pause to dedicated key codes.
+	Fix AVRCP keycodes to better match existing X keymap support.
+	Fix various quoting issues within telephony support.
+	Fix memory allocation issue when generating PDUs for SDP.
+	Fix race condition on device removal.
+	Fix non-cancelable issue with CreateDevice method.
+	Fix non-working CancelDiscovery method call.
+
+ver 4.39:
+	Add workaround for dealing with unknown inquiry complete.
+	Fix discovering when using software scheduler.
+	Fix wrong NoInputNoOutput IO capability string.
+	Fix race condition with agent during pairing.
+	Fix agent cancellation for security mode 3 acceptor failure.
+	Fix temporary flag removal when device creation fails.
+	Fix hciattach to use ppoll instead of poll.
+	Fix service class update when adapter is down.
+	Fix service classes race condition during startup.
+	Fix release of audio client before freeing the device.
+
+ver 4.38:
+	Add support for builtin plugins.
+	Add framework for adapter operations.
+	Add constants for Enhanced Retransmission modes.
+	Fix HCI socket leak in device_remove_bonding.
+	Fix various format string issues.
+	Fix crashes with various free functions.
+	Fix issues with Headset and A2DP drivers to load again.
+	Fix sending AVRCP button released passthrough messages
+	Fix bug which prevent input devices to work after restart.
+	Fix issue with interpretation of UUID-128 as channel.
+
+ver 4.37:
+	Add version value for Bluetooth 3.0 devices.
+	Add additional L2CAP extended feature mask bits.
+	Add support for loading plugins in priority order.
+	Add support for more detailed usage of disconnect watches.
+	Add support for AVRCP volume control.
+	Add saturated clipping of SBC decoder output to 16-bit.
+	Fix potentially infinite recursion of adapter_up.
+	Fix SCO handling in the case of an incoming call.
+	Fix input service to use confirm callback.
+	Fix cleanup of temporary device entries from storage.
+
+ver 4.36:
+	Add proper tracking of AVCTP connect attempts.
+	Add support to channel pattern in Serial interface.
+	Fix A2DP sink crash if removing device while connecting.
+	Fix error handling if HFP indicators aren't initialized.
+	Fix segfault while handling an incoming SCO connection.
+	Fix Serial.Disconnect to abort connection attempt.
+
+ver 4.35:
+	Add support for Handsfree profile headset role.
+	Add additional checks for open SEIDs from clients.
+	Fix device removal while audio IPC client is connected.
+	Fix device removal when an authorization request is pending.
+	Fix incoming AVDTP connect while authorization in progress.
+	Fix disconnection timers for audio support.
+	Fix various potential NULL pointer deferences.
+	Fix callheld indicator value for multiple calls.
+	Fix voice number type usage.
+	Fix GDBus watch handling.
+
+ver 4.34:
+	Add support for version checks of plugins.
+	Add support for class property on adapter interface.
+	Add support for second SDP attempt after connection reset.
+	Add support for more detailed audio states.
+	Add support for HFP+A2DP auto connection feature.
+	Add support for new and improved audio IPC.
+	Add program for testing audio IPC interface.
+	Fix various AVDTP qualification related issues.
+	Fix broken SDP AttributeIdList parsing.
+	Fix invalid memory access of SDP URL handling.
+	Fix local class of device race conditions.
+	Fix issue with periodic inquiry on startup.
+	Fix missing temporary devices in some situations.
+	Fix SBC alignment issue for encoding with four subbands.
+
+ver 4.33:
+	Add Paired property to the DeviceFound signals.
+	Add support for Headset profile 1.2 version.
+	Fix broken network configuration when IPv6 is disabled.
+	Fix network regression that caused disconnection.
+	Fix SDP truncation of strings with NULL values.
+	Fix service discovery handling of CUPS helper.
+
+ver 4.32:
+	Fix broken SDP record handling.
+	Fix SDP data buffer parsing.
+	Fix more SDP memory leaks.
+	Fix read scan enable calls.
+	Fix A2DP stream handling.
+
+ver 4.31:
+	Add support for new BtIO helper library.
+	Fix AVDTP session close issue.
+	Fix SDP memory leaks.
+	Fix various uninitialized memory issues.
+	Fix duplicate signal emissions.
+	Fix property changes request handling.
+	Fix class of device storage handling.
+
+ver 4.30:
+	Add CID field to L2CAP socket address structure.
+	Fix reset of authentication requirements after bonding.
+	Fix storing of link keys when using dedicated bonding.
+	Fix storing of pre-Bluetooth 2.1 link keys.
+	Fix resetting trust settings on every reboot.
+	Fix handling of local name changes.
+	Fix memory leaks in hciconfig and hcitool
+
+ver 4.29:
+	Use AVRCP version 1.0 for now.
+	Decrease AVDTP idle timeout to one second.
+	Delay AVRCP connection when remote device connects A2DP.
+	Add workaround for AVDTP stream setup with broken headsets.
+	Add missing three-way calling feature bit for Handsfree.
+	Fix handsfree callheld indicator updating.
+	Fix parsing of all AT commands within the buffer.
+	Fix authentication replies when disconnected.
+	Fix handling of debug combination keys.
+	Fix handling of changed combination keys.
+	Fix handling of link keys when using no bonding.
+	Fix handling of invalid/unknown authentication requirements.
+	Fix closing of L2CAP raw socket used for dedicated bonding.
+
+ver 4.28:
+	Add AVDTP signal fragmentation support.
+	Add more SBC performance optimizations.
+	Add more SBC audio quality improvements.
+	Use native byte order for audio plugins.
+	Set the adapter alias only after checking the EIR data.
+	Fix auto-disconnect issue with explicit A2DP connections.
+	Fix invalid memory access of ALSA plugin.
+	Fix compilation with -Wsign-compare.
+
+ver 4.27:
+	Add more SBC optimization (MMX and ARM NEON).
+	Add BT_SECURITY and BT_DEFER_SETUP definitions.
+	Add support for deferred connection setup.
+	Add support for fragmentation of data packets.
+	Add option to trigger dedicated bonding.
+	Follow MITM requirements from remote device.
+	Require MITM for dedicated bonding if capabilities allow it.
+	Fix IO capabilities for non-pairing and pairing cases.
+	Fix no-bonding connections in non-bondable mode.
+	Fix new pairing detection with SSP.
+	Fix bonding with pre-2.1 devices and newer kernels.
+	Fix LIAC setting while toggling Pairable property.
+	Fix device creation for incoming security mode 3 connects.
+	Fix crash within A2DP with bogus pointer.
+	Fix issue with sdp_copy_record() function.
+	Fix crash with extract_des() if sdp_uuid_extract() fails.
+
+ver 4.26:
+	Use of constant shift in SBC quantization code.
+	Add possibility to analyze 4 blocks at once in encoder.
+	Fix correct handling of frame sizes in the encoder.
+	Fix for big endian problems in SBC codec.
+	Fix audio client socket to always be non-blocking.
+	Update telephony support for Maemo.
+
+ver 4.25:
+	Fix receiving data over the audio control socket.
+	Fix subbands selection for joint-stereo in SBC encoder.
+	Add new SBC analysis filter function.
+
+ver 4.24:
+	Fix signal emissions when removing adapters.
+	Fix missing adapter signals on exit.
+	Add support for bringing adapters down on exit.
+	Add support for RememberPowered option.
+	Add support for verbose compiler warnings.
+	Add more options to SBC encoder.
+
+ver 4.23:
+	Update audio IPC for better codec handling.
+	Fix bitstream optimization for SBC encoder.
+	Fix length header values of IPC messages.
+	Fix multiple coding style violations.
+	Fix FindDevice to handle temporary devices.
+	Add configuration option for DeviceID.
+	Add support for InitiallyPowered option.
+	Add missing signals for manager properties.
+	Add telephony support for Maemo.
+
+ver 4.22:
+	Add deny statements to D-Bus access policy.
+	Add support for LegacyPairing property.
+	Add support for global properties.
+	Add more commands to telephony testing script.
+	Add sender checks for serial and network interfaces.
+	Remove deprecated methods and signals from input interface.
+	Remove deprecated methods and signals from network interface.
+	Remove OffMode option and always use device down.
+
+ver 4.21:
+	Fix adapter initialization logic.
+	Fix adapter setup and start security manager early.
+	Fix usage issue with first_init variable.
+
+ver 4.20:
+	Cleanup session handling.
+	Cleanup mode setting handling.
+	Fix issue with concurrent audio clients.
+	Fix issue with HFP/HSP suspending.
+	Fix AT result code syntax handling.
+	Add Handsfree support for AT+NREC.
+	Add PairableTimeout adapter property.
+
+ver 4.19:
+	Fix installation of manual pages for old daemons.
+	Fix D-Bus signal emmissions for CreateDevice.
+	Fix issues with UUID probing.
+	Fix +BSRF syntax issue.
+	Add Pairable adapter property.
+	Add sdp_copy_record() library function.
+
+ver 4.18:
+	Fix release before close issue with RFCOMM TTYs.
+	Fix Connected property on input interface.
+	Fix DeviceFound signals during initial name resolving.
+	Fix service discovery handling.
+	Fix duplicate UUID detection.
+	Fix SBC gain mismatch and decoding handling.
+	Add more options to SBC encoder and decoder.
+	Add special any adapter object for service interface.
+	Add variable prefix to adapter and device object paths.
+
+ver 4.17:
+	Fix SBC encoder not writing last frame.
+	Fix missing timer for A2DP suspend.
+	Add more supported devices to hid2hci utility.
+	Add additional functionality to Handsfree support.
+
+ver 4.16:
+	Fix wrong parameter usage of watch callbacks.
+	Fix parameters for callback upon path removal.
+	Fix unloading of adapter drivers.
+
+ver 4.15:
+	Fix various A2DP state machine issues.
+	Fix some issues with the Handsfree error reporting.
+	Fix format string warnings with recent GCC versions.
+	Remove dependency on GModule.
+
+ver 4.14:
+	Fix types of property arrays.
+	Fix potential crash with input devices.
+	Fix PS3 BD remote input event generation.
+	Allow dynamic adapter driver registration.
+	Update udev rules.
+
+ver 4.13:
+	Fix service discovery and UUID handling.
+	Fix bonding issues with Simple Pairing.
+	Fix file descriptor misuse of SCO connections.
+	Fix various memory leaks in the device handling.
+	Fix AVCTP disconnect handling.
+	Fix GStreamer modes for MP3 encoding.
+	Add operator selection to Handsfree support.
+
+ver 4.12:
+	Fix crash with missing icon value.
+	Fix error checks of HAL plugin.
+	Fix SCO server socket cleanup on exit.
+	Fix memory leaks from DBusPendingCall.
+	Fix handling of pending authorization requests.
+	Fix missing protocol UUIDs in record pattern.
+
+ver 4.11:
+	Change SCO server socket into a generic one.
+	Add test script for dummy telephony plugin.
+	Fix uninitialized reply of multiple GetProperties methods.
+
+ver 4.10:
+	Fix memory leaks with HAL messages.
+	Add more advanced handsfree features.
+	Add properties to audio, input and network interfaces.
+	Stop device discovery timer on device removal.
+
+ver 4.9:
+	Fix signals for Powered and Discoverable properties.
+	Fix handling of Alias and Icon properties.
+	Fix duplicate entries for service UUIDs.
+
+ver 4.8:
+	Fix retrieving of formfactor value.
+	Fix retrieving of local and remote extended features.
+	Fix potential NULL pointer dereference during pairing.
+	Fix crash with browsing due to a remotely initated pairing.
+
+ver 4.7:
+	Fix pairing and service discovery logic.
+	Fix crashes during suspend and resume.
+	Fix race condition within devdown mode.
+	Add RequestSession and ReleaseSession methods.
+	Add Powered and Discoverable properties.
+	Add Devices property and deprecate ListDevices.
+	Add workaround for a broken carkit from Nokia.
+
+ver 4.6:
+	Fix Device ID record handling.
+	Fix service browsing and storage.
+	Fix authentication and encryption for input devices.
+	Fix adapter name initialization.
+
+ver 4.5:
+	Fix initialization issue with new adapters.
+	Send HID authentication request without blocking.
+	Hide the verbose SDP debug behind SDP_DEBUG.
+	Add extra UUIDs for service discovery.
+	Add SCO server socket listener.
+	Add authorization support to service plugin.
+
+ver 4.4:
+	Add temporary fix for the CUPS compile issue.
+	Add service-api.txt to distribution.
+	Mention the variable prefix of an object path
+
+ver 4.3:
+	Add dummy driver for telephony support.
+	Add support for discovery sessions.
+	Add service plugin for external services.
+	Various cleanups.
+
+ver 4.2:
+	Avoid memory copies in A2DP write routine.
+	Fix broken logic with Simple Pairing check and old kernels.
+	Allow non-bondable and outgoing SDP without agent.
+	Only remove the bonding for non-temporary devices.
+	Cleanup various unnecessary includes.
+	Make more unexported functions static.
+	Add basic infrastructure for gtk-doc support.
+
+ver 4.1:
+	Add 30 seconds timeout to BNEP connection setup phase.
+	Avoid memory copies in A2DP write routine for ALSA.
+	Make sure to include compat/sdp.h in the distribution.
+
+ver 4.0:
+	Initial public release.
+
+ver 3.36:
+	Add init routines for TI BRF chips.
+	Add extra attributes to the serial port record.
+	Add example record for headset audio gateway record.
+	Use Handsfree version 0x0105 for the gateway role.
+	Fix SDP record registration with specific record handles.
+	Fix BCSP sent/receive handling.
+	Fix various includes for cross-compilation.
+	Allow link mode settings for outgoing connections.
+	Allow bonding during periodic inquiry.
+
+ver 3.35:
+	Add two additional company identifiers.
+	Add UUID-128 support for service discovery.
+	Fix usage of friendly names for service discovery.
+	Fix authorization when experiemental is disabled.
+	Fix uninitialized variable in passkey request handling.
+	Enable output of timestamps for l2test and rctest.
+
+ver 3.34:
+	Replace various SDP functions with safe versions.
+	Add additional length validation for incoming SDP packets.
+	Use safe function versions for SDP client handling.
+	Fix issue with RemoveDevice during discovery procedure.
+	Fix collect for non-persistent service records.
+
+ver 3.33:
+	Add functions for reading and writing the link policy settings.
+	Add definition for authentication requirements.
+	Add support for handling Simple Pairing.
+	Add Simple Pairing support to Agent interface.
+	Add ReleaseMode method to Adapter interface.
+	Add DiscoverServices method to Device interface.
+	Remove obsolete code and cleanup the repository.
+	Move over to use the libgdbus API.
+	Enable PIE by default if supported.
+
+ver 3.32:
+	Add OCF constants for synchronous flow control enabling.
+	Add support for switching HID proxy devices from Dell.
+	Add more Bluetooth client/server helper functions.
+	Add support for input service idle timeout option.
+	Fix BNEP reconnection handling.
+	Fix return value for snd_pcm_hw_params() calls.
+	Use upper-case addresses for object paths.
+	Remove HAL support helpers.
+	Remove inotify support.
+	Remove service daemon activation handling.
+	Remove uneeded D-Bus API extension.
+
+ver 3.31:
+	Create device object for all pairing cases.
+	Convert authorization to internal function calls.
+	Add initial support for Headset Audio Gateway role.
+	Add generic Bluetooth helper functions for GLib.
+	Fix endiannes handling of connection handles.
+	Don't optimize when debug is enabled.
+
+ver 3.30:
+	Convert audio service into a plugin.
+	Convert input service into a plugin.
+	Convert serial service into a plugin.
+	Convert network service into a plugin.
+	Emit old device signals when a property is changed.
+	Fix missing DiscoverDevices and CancelDiscovery methods.
+	Add another company identifier.
+	Add basic support for Bluetooth sessions.
+	Add avinfo utility for AVDTP/A2DP classification.
+	Remove build option for deprecated sdpd binary.
+
+ver 3.29:
+	Introduce new D-Bus based API.
+	Add more SBC optimizations.
+	Add support for PS3 remote devices.
+	Fix alignment trap in SDP server.
+	Fix memory leak in sdp_get_uuidseq_attr function.
+
+ver 3.28:
+	Add support for MCAP UUIDs.
+	Add support for role switch for audio service.
+	Add disconnect timer for audio service.
+	Add disconnect detection to ALSA plugin.
+	Add more SBC optimizations.
+	Fix alignment issue of SDP server.
+	Remove support for SDP parsing via expat.
+
+ver 3.27:
+	Update uinput.h with extra key definitions.
+	Add support for input connect/disconnect callbacks.
+	Add ifdefs around some baud rate definitions.
+	Add another company identifier.
+	Add proper HFP service level connection handling.
+	Add basic headset automatic disconnect support.
+	Add support for new SBC API.
+	Fix SBC decoder noise at high bitpools.
+	Use 32-bit multipliers for further SBC optimization.
+	Check for RFCOMM connection state in SCO connect callback.
+	Make use of parameters selected in ALSA plugin.
+
+ver 3.26:
+	Fix compilation issues with UCHAR_MAX, USHRT_MAX and UINT_MAX.
+	Improve handling of different audio transports.
+	Enable services by default and keep old daemons disabled.
+
+ver 3.25:
+	Add limited support for Handsfree profile.
+	Add limited support for MPEG12/MP3 codec.
+	Add basic support for UNITINFO and SUBUNITINFO.
+	Add more SBC optimizations.
+	Fix external service (un)registration.
+	Allow GetInfo and GetAddress to fail.
+
+ver 3.24:
+	Add definitions for MDP.
+	Add TCP connection support for serial proxy.
+	Add fix for Logitech HID proxy switching.
+	Add missing macros, MIN, MAX, ABS and CLAMP.
+	Add more SBC encoder optimizations.
+	Add initial mechanism to handle headset commands.
+	Fix connecting to handsfree profile headsets.
+	Use proper function for checking signal name.
+
+ver 3.23:
+	Fix remote name request handling bug.
+	Fix key search function to honor the mmap area size.
+	Fix Avahi integration of network service.
+	Add new plugin communication for audio service.
+	Enable basic AVRCP support by default.
+	More optimizations to the SBC library.
+	Create common error definitions.
+
+ver 3.22:
+	Add missing include file from audio service.
+	Add SBC conformance test utility.
+	Add basic uinput support for AVRCP.
+	Fix L2CAP socket leak in audio service.
+	Fix buffer usage in GStreamer plugin.
+	Fix remote name request event handling.
+
+ver 3.21:
+	Add constant for Bluetooth socket options level.
+	Add initial AVRCP support.
+	Add A2DP sink support to GStreamer plugin.
+	Fix interoperability with A2DP suspend.
+	Fix sign error in 8-subband encoder.
+	Fix handling of service classes length size.
+	Store Extended Inquiry Response data information.
+	Publish device id information through EIR.
+	Support higher baud rates for Ericcson based chips.
+
+ver 3.20:
+	Fix GStreamer plugin file type detection.
+	Fix potential infinite loop in inotify support.
+	Fix D-Bus signatures for dict handling.
+	Fix issues with service activation.
+	Fix SDP failure handling of audio service.
+	Fix various memory leaks in input service.
+	Add secure device creation method to input service.
+	Add service information methods to serial service.
+	Add config file support to network service.
+	Add scripting capability to network service.
+	Add special on-mode handling.
+	Add optimization for SBC encoder.
+	Add tweaks for D-Bus 1.1.x libraries.
+	Add support for inquiry transmit power level.
+
+ver 3.19:
+	Limit range of bitpool announced while in ACP side.
+	Use poll instead of usleep to wait for worker thread.
+	Use default event mask from the specification.
+	Add L2CAP mode constants.
+	Add HID proxy support for Logitech diNovo Edge dongle.
+	Add refresh option to re-request device names.
+	Show correct connection link type.
+
+ver 3.18:
+	Don't allocate memory for the Bluetooth base UUID.
+	Implement proper locking for headsets.
+	Fix various A2DP SEP locking issues.
+	Fix and cleanup audio stream handling.
+	Fix stream starting if suspend request is pending.
+	Fix A2DP and AVDTP endianess problems.
+	Add network timeout and retransmission support.
+	Add more detailed decoding of EIR elements.
+
+ver 3.17:
+	Fix supported commands bit calculation.
+	Fix crashes in audio and network services.
+	Check PAN source and destination roles.
+	Only export the needed symbols for the plugins.
+
+ver 3.16:
+	Update company identifier list.
+	Add support for headsets with SCO audio over HCI.
+	Add support for auto-create through ALSA plugin.
+	Add support for ALSA plugin parameters.
+	Add GStreamer plugin with SBC decoder and encoder.
+	Fix network service NAP, GN and PANU servers.
+	Set EIR information from SDP database.
+
+ver 3.15:
+	Add A2DP support to the audio service.
+	Add proxy support to the serial service.
+	Extract main service class for later use.
+	Set service classes value from SDP database.
+
+ver 3.14:
+	Add missing signals for the adapter interface.
+	Add definitions and functions for Simple Pairing.
+	Add basic commands for Simple Pairing.
+	Add correct Simple Pairing and EIR interaction.
+	Add missing properties for remote information.
+	Add EPoX endian quirk to the input service.
+	Fix HID descriptor import and storage functions.
+	Fix handling of adapters in raw mode.
+	Fix remote device listing methods.
+
+ver 3.13:
+	Fix some issues with the headset support.
+	Fix concurrent pending connection attempts.
+	Fix usage of devname instead of netdev.
+	Add identifier for Nokia SyncML records.
+	Add command for reading the CSR chip revision.
+	Add generic CSR radio test support.
+	Update HCI command table.
+
+ver 3.12:
+	Add missing HCI command text descriptions
+	Add missing HCI commands structures.
+	Add missing HCI event structures.
+	Add common bachk() function.
+	Add support for limited discovery mode.
+	Add support for setting of event mask.
+	Add GetRemoteServiceIdentifiers method.
+	Add skeleton for local D-Bus server.
+	Add headset gain control methods.
+	Fix various headset implementation issues.
+	Fix various serial port service issues.
+	Fix various input service issues.
+	Let CUPS plugin discover printers in range.
+	Improve the BCM2035 UART init routine.
+	Ignore connection events for non-ACL links.
+
+ver 3.11:
+	Update API documentation.
+	Minimize SDP root records and browse groups.
+	Use same decoder for text and URL strings.
+	Fix URL data size handling.
+	Fix SDP pattern extraction for XML.
+	Fix network connection persistent state.
+	Add network connection helper methods.
+	Add initial version of serial port support.
+	Add class of device tracking.
+
+ver 3.10.1:
+	Add option to disable installation of manual pages.
+	Fix input service encryption setup.
+	Fix serial service methods.
+	Fix network service connection handling.
+	Provide a simple init script.
+
+ver 3.10:
+	Add initial version of network service.
+	Add initial version of serial service.
+	Add initial version of input service.
+	Add initial version of audio service.
+	Add authorization framework.
+	Add integer based SBC library.
+	Add version code for Bluetooth 2.1 specification.
+	Add ESCO_LINK connection type constant.
+	Export sdp_uuid32_to_uuid128() function.
+
+ver 3.9:
+	Add RemoteDeviceDisconnectRequested signal.
+	Add updated service framework.
+	Add embedded GLib library.
+	Add support for using system GLib library.
+	Create internal SDP server library.
+
+ver 3.8:
+	Sort discovered devices list based on their RSSI.
+	Send DiscoverableTimeoutChanged signal.
+	Fix local and remote name validity checking.
+	Add ListRemoteDevices and ListRecentRemoteDevices methods.
+	Add basic integration of confirmation concept.
+	Add support for service record description via XML.
+	Add support for external commands to the RFCOMM utility.
+	Add experimental service and authorization API.
+	Add functions for registering binary records.
+
+ver 3.7:
+	Fix class of device handling.
+	Fix error replies with pairing and security mode 3.
+	Fix disconnect method for RFCOMM connections.
+	Add match pattern for service searches.
+	Add support for prioritized watches.
+	Add additional PDU length checks.
+	Fix CSRC value for partial responses.
+
+ver 3.6.1:
+	Fix IO channel race conditions.
+	Fix pairing issues on big endian systems.
+	Fix pairing issues with page timeout errors.
+	Fix pairing state for security mode 3 requests.
+	Switch to user as default security manager mode.
+
+ver 3.6:
+	Update D-Bus based RFCOMM interface support.
+	Use L2CAP raw sockets for HCI connection creation.
+	Add periodic discovery support to the D-Bus interface.
+	Add initial support for device names via EIR.
+	Add proper UTF-8 validation of device names.
+	Add support for the J-Three keyboard.
+	Fix issues with the asynchronous API for SDP.
+
+ver 3.5:
+	Fix and cleanup watch functionality.
+	Add support for periodic inquiry mode.
+	Add support for asynchronous SDP requests.
+	Add more request owner tracking.
+	Add asynchronous API for SDP.
+	Document pageto and discovto options.
+
+ver 3.4:
+	Improve error reporting for failed HCI commands.
+	Improve handling of CancelBonding.
+	Fixed bonding reply message when disconnected.
+	Fix UUID128 string lookup handling.
+	Fix malloc() versus bt_malloc() usage.
+
+ver 3.3:
+	Don't change inquiry mode for Bluetooth 1.1 adapters.
+	Add udev rules for Bluetooth serial PCMCIA cards.
+	Add Cancel and Release methods for passkey agents.
+	Add GetRemoteClass method.
+	Convert to using ppoll() and pselect().
+	Initialize allocated memory to zero.
+	Remove bcm203x firmware loader.
+	Remove kernel specific timeouts.
+	Add additional private data field for SDP sessions.
+	Add host controller to host flow control defines.
+	Add host number of completed packets defines.
+	Initialize various memory to zero before usage.
+
+ver 3.2:
+	Only check for the low-level D-Bus library.
+	Update possible device minor classes.
+	Fix timeout for pending reply.
+	Add more Inquiry with RSSI quirks.
+	Sleep only 100 msecs for device detection.
+	Don't send BondingCreated on link key renewal.
+	Allow storing of all UTF-8 remote device names.
+	Create storage filenames with a generic function.
+	Fix handling of SDP strings.
+	Add adapter type for SDIO cards.
+	Add features bit for link supervision timeout.
+
+ver 3.1:
+	Add missing placeholders for feature bits.
+	Fix handling of raw mode devices.
+	Fix busy loop in UUID extraction routine.
+	Remove inquiry mode setting.
+	Remove auth and encrypt settings.
+
+ver 3.0:
+	Implement the new BlueZ D-Bus API.
+	Fix broken behavior with EVT_CMD_STATUS.
+	Add features bit for pause encryption.
+	Add additional EIR error code.
+	Add more company identifiers.
+	Add another Phonebook Access identifier.
+	Update sniff subrating data structures.
+
+ver 2.25:
+	Use %jx instead of %llx for uint64_t and int64_t.
+	Allow null-terminated text strings.
+	Add UUID for N-Gage games.
+	Add UUID for Apple Macintosh Attributes.
+	Add Apple attributes and iSync records.
+	Add definitions for Apple Agent.
+	Add support for the Handsfree Audio Gateway service.
+	Add support for choosing a specific record handle.
+	Add support for dialup/telephone connections.
+	Add definitions for Apple Agent.
+	Add support for record handle on service registration.
+
+ver 2.24:
+	Fix display of SDP text and data strings.
+	Add support for device scan property.
+	Add support for additional access protocols.
+	Update the D-Bus policy configuration file.
+
+ver 2.23:
+	Update the new D-Bus interface.
+	Make dfutool ready for big endian architectures.
+	Add support for AVRCP specific service records.
+	Add support for writing complex BCCMD commands.
+	Add the new BCCMD interface utility.
+	Add MicroBCSP implementation from CSR.
+	Add constants and definitions for sniff subrating.
+	Add support for allocation of binary text elements.
+	Add HCI emulation tool.
+	Add fake HID support for old EPoX presenters.
+	Reject connections from unknown HID devices.
+	Fix service discovery deadlocks with Samsung D600 phones.
+
+ver 2.22:
+	Remove D-Bus 0.23 support.
+	Add initial version of the new D-Bus interface.
+	Add support for extended inquiry response commands.
+	Add support for the Logitech diNovo Media Desktop Laser.
+	Add compile time buffer checks (FORTIFY SOURCE).
+	Decode reserved LMP feature bits.
+	Fix errno overwrite problems.
+	Fix profile descriptor problem with Samsung phones.
+
+ver 2.21:
+	Move create_dirs() and create_file() into the textfile library.
+	Let textfile_put() also replace the last key value pair.
+	Fix memory leaks with textfile_get() usage.
+	Fix infinite loops and false positive matches.
+	Don't retrieve stored link keys for RAW devices.
+	Document the putkey and delkey commands.
+	Show supported commands also in clear text.
+	Support volatile changes of the BD_ADDR for CSR chips.
+	Add support for identification of supported commands.
+	Add missing OCF declarations for the security filter.
+	Add two new company identifiers.
+
+ver 2.20:
+	Add UUIDs for video distribution profile.
+	Add UUIDs for phonebook access profile.
+	Add attribute identifier for supported repositories.
+	Add definitions for extended inquiry response.
+	Add functions for extended inquiry response.
+	Add support for extended inquiry response.
+	Add support for HotSync service record.
+	Add support for ActiveSync service record.
+	Add ActiveSync networking support.
+	Fix D-Bus crashes with new API versions.
+
+ver 2.19:
+	Fix the GCC 4.0 warnings.
+	Fix the routing for dealing with raw devices.
+	Fix off by one memory allocation error.
+	Fix security problem with escape characters in device name.
+	Add per device service record functions.
+	Send D-Bus signals for inquiry results and remote name resolves.
+	Add support for device specific SDP records.
+
+ver 2.18:
+	Support D-Bus 0.23 and 0.33 API versions.
+	Support reading of complex BCCMD values.
+	Support minimum and maximum encryption key length.
+	Add support for reading and writing the inquiry scan type.
+	Add definitions for connection accept timeout and scan enable.
+	Add support for inquiry scan type.
+	Add tool for the CSR BCCMD interface.
+	Add first draft of the Audio/Video control utility.
+	Add disconnect timer support for the A2DP ALSA plugin.
+	Make SBC parameters configurable.
+	Replace non-printable characters in device names.
+	Remove hci_vhci.h header file.
+	Remove hci_uart.h header file.
+
+ver 2.17:
+	Set the storage directory through ${localstatedir}.
+	Add the textfile library for ASCII based file access.
+	Add support for return link keys event.
+	Add support for voice setting configuration.
+	Add support for page scan timeout configuration.
+	Add support for storing and deleting of stored link keys.
+	Add support for searching for services with UUID-128.
+	Add support for retrieving all possible service records.
+	Add support for a raw mode view of service records.
+	Add support for HID information caching in hidd.
+	Add support for authentication in pand and dund.
+	Add support for changing BD_ADDR of CSR chips.
+	Add pskey utility for changing CSR persistent storage values.
+	Add the firmware upgrade utility.
+	Add connection caching for the A2DP ALSA plugin.
+	Add functions for stored link keys.
+	Add definitions for PIN type and unit key.
+	Add SDP_WAIT_ON_CLOSE flag for sdp_connect().
+	Include stdio.h in bluetooth.h header file.
+	Include sys/socket.h in the header files.
+
+ver 2.16:
+	Store link keys in ASCII based file format.
+	Support device name caching.
+	Support zero length data sizes in l2test.
+	Change default l2ping data size to 44 bytes.
+	Hide the server record and the public browse group root.
+	Read BD_ADDR if not set and if it is a raw device.
+	Add SDP language attributes.
+	Add support for browsing the L2CAP group.
+	Add support for stored pin codes for outgoing connections.
+	Add support for local commands and extended features.
+	Add support for reading CSR panic and fault codes.
+	Add config option for setting the inquiry mode.
+	Add OUI decoding support.
+	Use unlimited inquiry responses as default.
+	Use cached device names for PIN request.
+	Use the clock offset when getting the remote names.
+	Add function for reading local supported commands.
+	Add function for reading local extended features.
+	Add function for reading remote extended features.
+	Add function for getting the remote name with a clock offset.
+	Add function for extracting the OUI from a BD_ADDR.
+	Add inquiry info structure with RSSI and page scan mode.
+	Fix buffer allocation for features to string conversion.
+	Support inquiry with unlimited number of responses.
+
+ver 2.15:
+	Enable the RFCOMM service level security.
+	Add deprecated functions for reading the name.
+	Add command for reading the clock offset.
+	Add command for reading the clock.
+	Add function for reading the clock.
+	Add function for reading the local Bluetooth address.
+	Add function for reading the local supported features.
+	Don't configure raw devices.
+	Don't set inquiry scan or page scan on raw devices.
+	Don't show extended information for raw devices.
+	Support L2CAP signal sizes bigger than 2048 bytes.
+	Cleanup of the socket handling code of the test programs.
+	Use better way for unaligned access.
+	Remove sdp_internal.h and its usage.
+
+ver 2.14:
+	Make use of additional connection information.
+	Use library function for reading the RSSI.
+	Use library function for reading the link quality.
+	Use library function for reading the transmit power level.
+	Use library functions for the link supervision timeout.
+	Add tool for changing the device address.
+	Add function for reading the RSSI.
+	Add function for reading the link quality.
+	Add function for reading the transmit power level.
+	Add functions for the link supervision timeout.
+	Remove deprecated functions.
+	Update AM_PATH_BLUEZ macro.
+
+ver 2.13:
+	Use file permission 0600 for the link key file.
+	Add support for HID attribute descriptions.
+	Add support for Device ID attributes.
+	Add Device ID and HID attribute definitions.
+	Update the UUID constants and its translations.
+	Update L2CAP socket option definitions.
+	Update connection information definitions.
+	Various whitespace cleanups.
+
+ver 2.12:
+	Inherit the device specific options from the default.
+	Use --device for selecting the source device.
+	Add --nosdp option for devices with resource limitation.
+	Add support and parameter option for secure mode.
+	Add a lot of build ids and hardware revisions.
+	Add service classes and profile ids for WAP.
+	Add simple AM_PATH_BLUEZ macro.
+	Update UUID translation tables.
+	Correct kernel interface for CMTP and HIDP support.
+
+ver 2.11:
+	Initial support for the kernel security manager.
+	Various cleanups to avoid inclusion of kernel headers.
+	Fix output when the CUPS backend is called without arguments.
+	Fix problems with a 64 bit userland.
+	Use Bluetooth library functions if available.
+	Use standard numbering scheme of SDP record handles.
+	Use bit zero for vendor packets in the filter type bitmask.
+	Add SIM Access types for service discovery.
+	Add more audio/video profile translations.
+	Add another company identifier.
+	Add the missing HCI error codes.
+	Add RFCOMM socket options.
+	Add definition for the SECURE link mode.
+	Add functions for reading and writing the inquiry mode.
+	Add functions for AFH related settings and information.
+	Add version identifier for the Bluetooth 2.0 specification.
+	Add a master option to the hidd.
+	Add support for changing the link key of a connection.
+	Add support for requesting encryption on keyboards.
+	Add support for revision information of Digianswer devices.
+	Add support for the Zoom, IBM and TDK PCMCIA cards.
+	Add checks for the OpenOBEX and the ALSA libraries.
+	Add experimental mRouter support.
+
+ver 2.10:
+	Use a define for the configuration directory.
+	Fix string initialization for flags translation.
+	Fix and extend the unaligned access macros.
+	Make compiling with debug information optional.
+	Don't override CFLAGS from configure.
+	Check for usb_get_busses() and usb_interrupt_read().
+	Add optional support for compiling with PIE.
+	Make installation of the init scripts optional.
+	Make compiling with debug information optional.
+	Don't override CFLAGS from configure.
+
+ver 2.9:
+	Retry SDP connect if busy in the CUPS backend.
+	Use packet type and allow role switch in hcitool.
+	Use the functions from the USB library for hid2hci.
+	Add Broadcom firmware loader.
+	Add EPoX endian quirk for buggy keyboards.
+	Add L2CAP info type and info result definitions.
+	Add value for L2CAP_CONF_RFC_MODE.
+	Change RSSI value to signed instead of unsigned.
+	Allow UUID32 values as protocol identifiers.
+	Update the autoconf/automake scripts.
+
+ver 2.8:
+	Use LIBS and LDADD instead of LDFLAGS.
+	Use HIDP subclass field for HID boot protocol.
+	Set olen before calling getsockopt() in pand.
+	Restore signals for dev-up script.
+	Add PID file support for pand.
+	Add size parameter to expand_name() in hcid.
+	Add support for audio source and audio sink SDP records.
+	Add support for HID virtual cable unplug.
+	Add support for AmbiCom BT2000C card.
+	Add defines and UUID's for audio/video profiles.
+	Add AVDTP protocol identifier.
+	Add HIDP subclass field.
+	Add PKGConfig support.
+	Fix the event code of inquiry with RSSI.
+	Remove dummy SDP library.
+
+ver 2.7:
+	Fix display of decoded LMP features.
+	Update company identifiers.
+	Add AFH related types.
+	Add first bits from EDR prototyping specification.
+	Add support for inquiry with RSSI.
+	Add HCRP related SDP functions.
+	Add HIDP header file.
+	Add support for getting the AFH channel map.
+	Add support for AFH mode.
+	Add support for inquiry mode.
+	Add Bluetooth backend for CUPS.
+	Add the hid2hci utility.
+	Add the hidd utility.
+	Add the pand utility.
+	Add the dund utility.
+	More endian bug fixes.
+	Give udev some time to create the RFCOMM device nodes.
+	Release the TTY if no device node is found.
+	New startup script for the Bluetooth subsystem.
+	Update to the autoconf stuff.
+
+ver 2.6:
+	Change default prefix to /usr.
+	Add manpages for hcid and hcid.conf.
+	Add the sdpd server daemon.
+	Add the sdptool utility.
+	Add the ciptool utility.
+	Add new company identifiers.
+	Add BNEP and CMTP header files.
+	Add the SDP library.
+	Use R2 for default value of pscan_rep_mode.
+
+ver 2.5:
+	Add decoding of Bluetooth 1.2 features.
+	Add link manager version parameter for Bluetooth 1.2.
+	Add new company identifiers.
+	Add D-Bus support for PIN request.
+	Support for transmit power level.
+	Support for park, sniff and hold mode.
+	Support for role switch.
+	Support for reading the clock offset.
+	Support for requesting authentication.
+	Support for setting connection encryption.
+	Show revision information for Broadcom devices.
+	Replace unprintable characters in device name.
+	Use R1 for default value of pscan_rep_mode.
+	Fix some 64-bit problems.
+	Fix some endian problems.
+	Report an error on PIN helper failure.
+	Update bluepin script for GTK2.
+
+ver 2.4:
+	Increase number of inquiry responses.
+	Support for transmit power level.
+	Display all 8 bytes of the features.
+	Add support for reading and writing of IAC.
+	Correct decoding class of device.
+	Use Ericsson revision command for ST Microelectronics devices.
+	Display AVM firmware version with 'revision' command.
+	New code for CSR specific revision information.
+	Support for ST Microelectronics specific initialization.
+	Support for 3Com card version 3.0.
+	Support for TDK, IBM and Socket cards.
+	Support for initial baud rate.
+	Update man pages.
+	Fixes for some memory leaks.
+
+ver 2.3:
+	Added const qualifiers to appropriate function arguments.
+	Minor fixes.
+	CSR firmware version is now displayed by 'revision' command.
+	Voice command is working properly on big endian machines.
+	Added support for Texas Bluetooth modules.
+	Added support for high UART baud rates on Ericsson modules.
+	BCSP initialization fixes.
+	Support for role switch command (hcitool).
+	RFCOMM config file parser fixes.
+	Update man pages.
+	Removed GLib dependency.
+
+ver 2.2:
+	Updated RFCOMM header file.
+	Additional HCI command and event defines.
+	Support for voice settings (hciconfig).
+	Minor hcitool fixes.
+	Improved configure script.
+	Added Headset testing tool.
+	Updated man pages.
+	RPM package.
+
+ver 2.1.1:
+	Resurrect hci_remote_name.
+
+ver 2.1:
+	Added hci_{read, write}_class_of_dev().
+	Added hci_{read, write}_current_iac_lap().
+	Added hci_write_local_name().
+	Added RFCOMM header file.
+	Minor fixes.
+	Improved BCSP initialization (hciattach).
+	Support for displaying link quality (hcitool).
+	Support for changing link supervision timeout (hcitool).
+	New RFCOMM TTY configuration tool (rfcomm).
+	Minor fixes and updates.
+
+ver 2.0:
+	Additional company IDs.
+	BCSP initialization (hciattach).
+	Minor hciconfig fixes.
+
+ver 2.0-pr13:
+	Support for multiple pairing modes.
+	Link key database handling fixes.
+
+ver 2.0-pre12:
+	Removed max link key limit. Keys never expire.
+	Link key database is always updated. Reread PIN on SIGHUP (hcid).
+	Bluetooth script starts SDPd, if installed.
+	Other minor fixes.
+
+ver 2.0-pre11:
+	Improved link key management and more verbose logging (hcid).
+	Fixed scan command (hcitool).
+
+ver 2.0-pre10:
+	Fix hci_inquiry function to return errors and accept user buffers.
+	New functions hci_devba, hci_devid, hci_for_each_dev and hci_get_route.
+	Additional company IDs.
+	Makefile and other minor fixes.
+	Support for reading RSSI, remote name and changing
+	connection type (hcitool). 
+	Device initialization fixes (hcid).
+	Other minor fixes and improvements.
+	Build environment cleanup and fixes.
+
+ver 2.0-pre9:
+	Improved bluepin. Working X authentication.
+	Improved hcitool. New flexible cmd syntax, additional commands.
+	Human readable display of the device features.
+	LMP features to string translation support.
+	Additional HCI command and event defines.
+	Extended hci_filter API.
+
+ver 2.0-pre8:
+	Additional HCI ioctls and defines.
+	All strings and buffers are allocated dynamically.
+	ba2str, str2ba automatically swap bdaddress.
+	Additional hciconfig commands. Support for ACL and SCO MTU ioctls.
+	Support for Inventel and COM1 UART based devices.
+	Minor hcitool fixes.
+	Improved l2test. New L2CAP test modes.
+	Minor fixes and cleanup.
+
+ver 2.0-pre7:
+	Bluetooth libraries and header files is now a separate package.
+	New build environment uses automake and libtool.
+	Massive header files cleanup.
+	Bluetooth utilities is now a separate package.
+	New build environment uses automake.
+	Moved all config files and security data to /etc/bluetooth.
+	Various cleanups.
+
+ver 2.0-pre6:
+	API cleanup and additions.
+	Improved hcitool.
+	l2test minor output fixes.
+	hciattach opt to display list of supported devices.
+
+ver 2.0-pre4:
+	HCI filter enhancements.
+
+ver 2.0-pre3:
+	Cleanup.
+
+ver 2.0-pre2:
+	Additional HCI library functions.
+	Improved CSR baud rate initialization.
+	PCMCIA scripts fixes and enhancements.
+	Documentation update.
+
+ver 2.0-pre1:
+	New UART initialization utility.
+	Hot plugging support for UART based PCMCIA devices.
+	SCO testing utility.
+	New authentication utility (bluepin).
+	Minor fixes and improvements.
diff --git a/repo/HACKING b/repo/HACKING
new file mode 100644
index 0000000..a8fb403
--- /dev/null
+++ b/repo/HACKING
@@ -0,0 +1,130 @@
+Hacking on BlueZ
+****************
+
+Build tools requirements
+========================
+
+When building and testing directly from the repository it is important to
+have at least automake version 1.10 or later installed. All modern
+distributions should default to the latest version, but it seems that
+Debian's default is still an earlier version:
+
+  Check version
+    # dpkg -l '*automake*'
+
+  Install new version
+    # apt-get install automake1.10
+    # update-alternatives --config automake
+
+
+Working with the source code repository
+=======================================
+
+The repository contains two extra scripts that accomplish the bootstrap
+process. One is called "bootstrap" which is the basic scripts that uses the
+autotools scripts to create the needed files for building and installing.
+It makes sure to call the right programs depending on the usage of shared or
+static libraries or translations etc.
+
+The second program is called "bootstrap-configure". This program will make
+sure to properly clean the repository, call the "bootstrap" script and then
+call configure with proper settings for development. It will use the best
+options and pass them over to configure. These options normally include
+the enabling the maintainer mode and the debugging features.
+
+So while in a normal source project the call "./configure ..." is used to
+configure the project with its settings like prefix and extra options. In
+case of bare repositories call "./bootstrap-configure" and it will bootstrap
+the repository and calls configure with all the correct options to make
+development easier.
+
+In case of preparing for a release with "make distcheck", don't use
+bootstrap-configure since it could export development specific settings.
+
+So the normal steps to checkout, build and install such a repository is
+like this:
+
+  Checkout repository
+    # git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git
+    # cd bluez
+
+  Configure and build
+    # ./bootstrap-configure
+    # make
+
+  Configure and build with cgcc (Sparse)
+    # ./bootstrap-configure CC=cgcc
+    # make
+
+  Run unit tests
+    # make check
+
+  Check installation
+    # make install DESTDIR=$PWD/x
+    # find x
+    # rm -rf x
+
+  Check distribution
+    # make distcheck
+
+  Final installation
+    # sudo make install
+
+  Remove autogenerated files
+    # make maintainer-clean
+
+
+Running from within the source code repository
+==============================================
+
+When using "./configure --enable-maintainer-mode" the automake scripts will
+use the plugins directly from within the repository. This removes the need
+to use "make install" when testing "bluetoothd". The "bootstrap-configure"
+automatically includes this option.
+
+  Copy configuration file which specifies the required security policies
+    # sudo cp ./src/bluetooth.conf /etc/dbus-1/system.d/
+
+  Run daemon in foreground with debugging
+    # sudo ./src/bluetoothd -n -d
+
+  Run daemon with valgrind
+   # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes \
+   --show-possibly-lost=no --leak-check=full --suppressions=./tools/valgrind.supp \
+   ./src/bluetoothd -n -d
+
+For production installations or distribution packaging it is important that
+the "--enable-maintainer-mode" option is NOT used.
+
+Note multiple arguments to -d can be specified, colon, comma or space
+separated. The arguments are relative source code filenames for which
+debugging output should be enabled; output shell-style globs are
+accepted (e.g.: 'plugins/*:src/main.c').
+
+Submitting patches
+==================
+
+If you fixed a bug or you want to add support for something, patches are
+welcome! In order to ease the inclusion of your patch, it's important to follow
+some rules, otherwise it will likely be rejected by maintainers.
+
+BlueZ rules for submitting patches follow most of the rules used by Linux kernel
+(https://www.kernel.org/doc/Documentation/SubmittingPatches) with some remarks:
+
+1) Do *not* add "Signed-off-by" lines in your commit messages. BlueZ does not
+use them, so including them is actually an error.
+
+2) Be sure to follow the coding style rules of BlueZ. They are listed in
+doc/coding-style.txt.
+
+3) Split your patch according to the top-level directories. E.g.: if you added
+a feature that touches files under 'include/', 'src/' and 'drivers/'
+directories, split in three separated patches, taking care not to
+break compilation.
+
+4) Bug fixes should be sent first as they take priority over new features.
+
+5) The commit message should follow 50/72 formatting which means the header
+should be limited to 50 characters and the description should be wrapped at 72
+characters except if it contains quoted information from debug tools like
+backtraces, compiler errors, etc.
diff --git a/repo/INSTALL b/repo/INSTALL
new file mode 100644
index 0000000..56b077d
--- /dev/null
+++ b/repo/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/repo/Makefile.am b/repo/Makefile.am
new file mode 100644
index 0000000..3e1d8d0
--- /dev/null
+++ b/repo/Makefile.am
@@ -0,0 +1,505 @@
+
+AM_MAKEFLAGS = --no-print-directory
+
+lib_LTLIBRARIES =
+
+noinst_LIBRARIES =
+
+noinst_LTLIBRARIES =
+
+bin_PROGRAMS =
+
+noinst_PROGRAMS =
+
+dist_man_MANS =
+
+dist_noinst_MANS =
+
+CLEANFILES =
+
+EXTRA_DIST =
+
+libexecdir = @libexecdir@/bluetooth
+
+libexec_PROGRAMS =
+
+includedir = @includedir@/bluetooth
+
+include_HEADERS =
+
+AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS)
+AM_LDFLAGS = $(MISC_LDFLAGS)
+
+if DATAFILES
+dbusdir = @DBUS_CONFDIR@/dbus-1/system.d
+dbus_DATA = src/bluetooth.conf
+
+confdir = $(sysconfdir)/bluetooth
+conf_DATA =
+
+statedir = $(localstatedir)/lib/bluetooth
+state_DATA =
+endif
+
+if SYSTEMD
+systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
+systemdsystemunit_DATA = src/bluetooth.service
+
+dbussystembusdir = @DBUS_SYSTEMBUSDIR@
+dbussystembus_DATA = src/org.bluez.service
+endif
+
+EXTRA_DIST += src/bluetooth.service.in src/org.bluez.service
+
+plugindir = $(libdir)/bluetooth/plugins
+
+if MAINTAINER_MODE
+build_plugindir = $(abs_top_srcdir)/plugins/.libs
+else
+build_plugindir = $(plugindir)
+endif
+
+
+plugin_LTLIBRARIES =
+
+lib_sources = lib/bluetooth.c lib/hci.c lib/sdp.c
+lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+		lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+		lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+
+extra_headers = lib/mgmt.h lib/uuid.h lib/a2mp.h lib/amp.h
+extra_sources = lib/uuid.c
+
+local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
+
+BUILT_SOURCES = $(local_headers) src/builtin.h
+
+if LIBRARY
+include_HEADERS += $(lib_headers)
+
+lib_LTLIBRARIES += lib/libbluetooth.la
+
+lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:10:18
+lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+endif
+
+noinst_LTLIBRARIES += lib/libbluetooth-internal.la
+
+lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \
+					$(extra_headers) $(extra_sources)
+
+noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
+
+gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \
+				gdbus/mainloop.c gdbus/watch.c \
+				gdbus/object.c gdbus/client.c gdbus/polkit.c
+
+noinst_LTLIBRARIES += src/libshared-glib.la src/libshared-mainloop.la
+
+shared_sources = src/shared/io.h src/shared/timeout.h \
+			src/shared/queue.h src/shared/queue.c \
+			src/shared/util.h src/shared/util.c \
+			src/shared/mgmt.h src/shared/mgmt.c \
+			src/shared/crypto.h src/shared/crypto.c \
+			src/shared/ecc.h src/shared/ecc.c \
+			src/shared/ringbuf.h src/shared/ringbuf.c \
+			src/shared/tester.h src/shared/tester.c \
+			src/shared/hci.h src/shared/hci.c \
+			src/shared/hci-crypto.h src/shared/hci-crypto.c \
+			src/shared/hfp.h src/shared/hfp.c \
+			src/shared/uhid.h src/shared/uhid.c \
+			src/shared/pcap.h src/shared/pcap.c \
+			src/shared/btsnoop.h src/shared/btsnoop.c \
+			src/shared/ad.h src/shared/ad.c \
+			src/shared/att-types.h \
+			src/shared/att.h src/shared/att.c \
+			src/shared/gatt-helpers.h src/shared/gatt-helpers.c \
+			src/shared/gatt-client.h src/shared/gatt-client.c \
+			src/shared/gatt-server.h src/shared/gatt-server.c \
+			src/shared/gatt-db.h src/shared/gatt-db.c \
+			src/shared/gap.h src/shared/gap.c
+
+src_libshared_glib_la_SOURCES = $(shared_sources) \
+				src/shared/io-glib.c \
+				src/shared/timeout-glib.c
+
+src_libshared_mainloop_la_SOURCES = $(shared_sources) \
+				src/shared/io-mainloop.c \
+				src/shared/timeout-mainloop.c \
+				src/shared/mainloop.h src/shared/mainloop.c
+
+attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
+		attrib/gatt.h attrib/gatt.c \
+		attrib/gattrib.h attrib/gattrib.c \
+		attrib/gatt-service.h attrib/gatt-service.c
+
+btio_sources = btio/btio.h btio/btio.c
+
+gobex_sources = gobex/gobex.h gobex/gobex.c \
+			gobex/gobex-defs.h gobex/gobex-defs.c \
+			gobex/gobex-packet.c gobex/gobex-packet.h \
+			gobex/gobex-header.c gobex/gobex-header.h \
+			gobex/gobex-transfer.c gobex/gobex-debug.h \
+			gobex/gobex-apparam.c gobex/gobex-apparam.h
+
+builtin_modules =
+builtin_sources =
+builtin_nodist =
+
+include Makefile.plugins
+
+if MAINTAINER_MODE
+plugin_LTLIBRARIES += plugins/external-dummy.la
+plugins_external_dummy_la_SOURCES = plugins/external-dummy.c
+plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+				    -no-undefined
+plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
+endif
+
+libexec_PROGRAMS += src/bluetoothd
+
+src_bluetoothd_SOURCES = $(builtin_sources) \
+			$(attrib_sources) $(btio_sources) \
+			src/bluetooth.ver \
+			src/main.c src/log.h src/log.c \
+			src/backtrace.h src/backtrace.c \
+			src/systemd.h src/systemd.c \
+			src/rfkill.c src/hcid.h src/sdpd.h \
+			src/sdpd-server.c src/sdpd-request.c \
+			src/sdpd-service.c src/sdpd-database.c \
+			src/attrib-server.h src/attrib-server.c \
+			src/gatt-database.h src/gatt-database.c \
+			src/sdp-xml.h src/sdp-xml.c \
+			src/sdp-client.h src/sdp-client.c \
+			src/textfile.h src/textfile.c \
+			src/uuid-helper.h src/uuid-helper.c \
+			src/uinput.h \
+			src/plugin.h src/plugin.c \
+			src/storage.h src/storage.c \
+			src/advertising.h src/advertising.c \
+			src/agent.h src/agent.c \
+			src/error.h src/error.c \
+			src/adapter.h src/adapter.c \
+			src/profile.h src/profile.c \
+			src/service.h src/service.c \
+			src/gatt-client.h src/gatt-client.c \
+			src/device.h src/device.c src/attio.h \
+			src/dbus-common.c src/dbus-common.h \
+			src/eir.h src/eir.c
+src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
+			gdbus/libgdbus-internal.la \
+			src/libshared-glib.la \
+			@BACKTRACE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
+				-Wl,--version-script=$(srcdir)/src/bluetooth.ver
+
+src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
+				gdbus/libgdbus-internal.la \
+				src/libshared-glib.la \
+				src/bluetooth.service
+
+src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
+					-DPLUGINDIR=\""$(build_plugindir)"\"
+src_bluetoothd_SHORTNAME = bluetoothd
+
+builtin_files = src/builtin.h $(builtin_nodist)
+
+nodist_src_bluetoothd_SOURCES = $(builtin_files)
+
+CLEANFILES += $(builtin_files) src/bluetooth.service
+
+man_MANS = src/bluetoothd.8
+
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+			src/main.conf profiles/network/network.conf \
+			profiles/input/input.conf profiles/proximity/proximity.conf
+
+test_scripts =
+unit_tests =
+
+include Makefile.tools
+include Makefile.obexd
+include android/Makefile.am
+
+if HID2HCI
+rulesdir = @UDEV_DIR@/rules.d
+
+rules_DATA = tools/97-hid2hci.rules
+
+CLEANFILES += $(rules_DATA)
+endif
+
+EXTRA_DIST += tools/hid2hci.rules
+
+if TEST
+testdir = $(pkglibdir)/test
+test_SCRIPTS = $(test_scripts)
+endif
+
+EXTRA_DIST += $(test_scripts)
+
+EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt \
+				doc/test-coverage.txt \
+				doc/test-runner.txt \
+				doc/settings-storage.txt
+
+EXTRA_DIST += doc/mgmt-api.txt \
+		doc/adapter-api.txt doc/device-api.txt \
+		doc/agent-api.txt doc/profile-api.txt \
+		doc/network-api.txt doc/media-api.txt \
+		doc/health-api.txt doc/sap-api.txt \
+		doc/input-api.txt
+
+EXTRA_DIST += doc/alert-api.txt \
+		doc/proximity-api.txt doc/heartrate-api.txt \
+		doc/thermometer-api.txt doc/cyclingspeed-api.txt \
+		doc/gatt-api.txt doc/advertising-api.txt
+
+EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
+
+EXTRA_DIST += doc/pics-opp.txt doc/pixit-opp.txt \
+		doc/pts-opp.txt
+
+EXTRA_DIST += tools/magic.btsnoop
+
+AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@ @UDEV_CFLAGS@
+
+AM_CPPFLAGS = -I$(builddir)/lib
+
+
+unit_tests += unit/test-eir
+
+unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/uuid-helper.c
+unit_test_eir_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+								@GLIB_LIBS@
+
+unit_tests += unit/test-uuid
+
+unit_test_uuid_SOURCES = unit/test-uuid.c
+unit_test_uuid_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+								@GLIB_LIBS@
+
+unit_tests += unit/test-textfile
+
+unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c
+unit_test_textfile_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-crc
+
+unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c
+unit_test_crc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-crypto
+
+unit_test_crypto_SOURCES = unit/test-crypto.c
+unit_test_crypto_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-ecc
+
+unit_test_ecc_SOURCES = unit/test-ecc.c
+unit_test_ecc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-ringbuf unit/test-queue
+
+unit_test_ringbuf_SOURCES = unit/test-ringbuf.c
+unit_test_ringbuf_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_test_queue_SOURCES = unit/test-queue.c
+unit_test_queue_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-mgmt
+
+unit_test_mgmt_SOURCES = unit/test-mgmt.c
+unit_test_mgmt_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-uhid
+
+unit_test_uhid_SOURCES = unit/test-uhid.c
+unit_test_uhid_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-sdp
+
+unit_test_sdp_SOURCES = unit/test-sdp.c \
+				src/sdpd.h src/sdpd-database.c \
+				src/log.h src/log.c \
+				src/sdpd-service.c src/sdpd-request.c
+unit_test_sdp_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avdtp
+
+unit_test_avdtp_SOURCES = unit/test-avdtp.c \
+				src/log.h src/log.c \
+				android/avdtp.c android/avdtp.h
+unit_test_avdtp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avctp
+
+unit_test_avctp_SOURCES = unit/test-avctp.c \
+				src/log.h src/log.c \
+				android/avctp.c android/avctp.h
+unit_test_avctp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avrcp
+
+unit_test_avrcp_SOURCES = unit/test-avrcp.c \
+				src/log.h src/log.c \
+				android/avctp.c android/avctp.h \
+				android/avrcp-lib.c android/avrcp-lib.h
+unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-hfp
+
+unit_test_hfp_SOURCES = unit/test-hfp.c
+unit_test_hfp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-gdbus-client
+
+unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
+unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@ @DBUS_LIBS@
+
+unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
+			unit/test-gobex-transfer unit/test-gobex-apparam
+
+unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex.c
+unit_test_gobex_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex-packet.c
+unit_test_gobex_packet_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex-header.c
+unit_test_gobex_header_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex-transfer.c
+unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex-apparam.c
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+
+unit_tests += unit/test-lib
+
+unit_test_lib_SOURCES = unit/test-lib.c
+unit_test_lib_LDADD = src/libshared-glib.la \
+				lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-gatt
+
+unit_test_gatt_SOURCES = unit/test-gatt.c
+unit_test_gatt_LDADD = src/libshared-glib.la \
+				lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-hog
+
+unit_test_hog_SOURCES = unit/test-hog.c \
+			$(btio_sources) \
+			profiles/input/hog-lib.h profiles/input/hog-lib.c \
+			profiles/scanparam/scpp.h profiles/scanparam/scpp.c \
+			profiles/battery/bas.h profiles/battery/bas.c \
+			profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \
+			src/log.h src/log.c \
+			attrib/att.h attrib/att.c \
+			attrib/gatt.h attrib/gatt.c \
+			attrib/gattrib.h attrib/gattrib.c
+unit_test_hog_LDADD = src/libshared-glib.la \
+				lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-gattrib
+
+unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c $(btio_sources) src/log.h src/log.c
+unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \
+			src/libshared-glib.la \
+			@GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+
+if MAINTAINER_MODE
+noinst_PROGRAMS += $(unit_tests)
+endif
+
+TESTS = $(unit_tests)
+AM_TESTS_ENVIRONMENT = MALLOC_CHECK_=3 MALLOC_PERTURB_=69
+
+if DBUS_RUN_SESSION
+AM_TESTS_ENVIRONMENT += dbus-run-session --
+endif
+
+if VALGRIND
+LOG_COMPILER = valgrind --error-exitcode=1 --num-callers=30
+LOG_FLAGS = --trace-children=yes --leak-check=full --show-reachable=no \
+		--suppressions=$(srcdir)/tools/valgrind.supp --quiet
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+if LIBRARY
+pkgconfig_DATA = lib/bluez.pc
+endif
+
+manual_pages = doc/btmon.1
+
+if MANPAGES
+dist_noinst_MANS += $(manual_pages)
+endif
+
+EXTRA_DIST += $(manual_pages:.1=.txt)
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \
+					--enable-manpages --enable-android \
+					--disable-systemd --disable-udev
+
+DISTCLEANFILES = $(pkgconfig_DATA) $(unit_tests) $(manual_pages)
+
+MAINTAINERCLEANFILES = Makefile.in \
+	aclocal.m4 configure config.h.in config.sub config.guess \
+	ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver
+
+SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
+		$(SED) -e 's,@libexecdir\@,$(libexecdir),g' \
+		< $< > $@
+
+%.service: %.service.in Makefile
+	$(SED_PROCESS)
+
+%.1: %.txt
+	$(AM_V_GEN)a2x --doctype manpage --format manpage $(srcdir)/$<
+
+src/builtin.h: src/genbuiltin $(builtin_sources)
+	$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+
+tools/%.rules:
+	$(AM_V_GEN)cp $(srcdir)/$(subst 97-,,$@) $@
+
+$(lib_libbluetooth_la_OBJECTS): $(local_headers)
+
+lib/bluetooth/%.h: lib/%.h
+	$(AM_V_at)$(MKDIR_P) lib/bluetooth
+	$(AM_V_GEN)$(LN_S) -f "$(abs_top_builddir)"/$< $@
+
+if COVERAGE
+clean-coverage:
+	@lcov --directory $(top_builddir) --zerocounters
+	$(RM) -r coverage $(top_builddir)/coverage.info
+
+coverage: check
+	@lcov --compat-libtool --directory $(top_builddir) --capture \
+				--output-file $(top_builddir)/coverage.info
+	$(AM_V_at)$(MKDIR_P) coverage
+	@genhtml -o coverage/ $(top_builddir)/coverage.info
+
+clean-local: clean-coverage
+	-find $(top_builddir) -name "*.gcno" -delete
+	-find $(top_builddir) -name "*.gcda" -delete
+	$(RM) -r lib/bluetooth
+
+else
+clean-local:
+	-find $(top_builddir) -name "*.gcno" -delete
+	-find $(top_builddir) -name "*.gcda" -delete
+	$(RM) -r lib/bluetooth
+endif
diff --git a/repo/Makefile.obexd b/repo/Makefile.obexd
new file mode 100644
index 0000000..2e33cbc
--- /dev/null
+++ b/repo/Makefile.obexd
@@ -0,0 +1,110 @@
+
+if SYSTEMD
+systemduserunitdir = @SYSTEMD_USERUNITDIR@
+systemduserunit_DATA = obexd/src/obex.service
+
+dbussessionbusdir = @DBUS_SESSIONBUSDIR@
+dbussessionbus_DATA = obexd/src/org.bluez.obex.service
+endif
+
+EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service
+
+obex_plugindir = $(libdir)/obex/plugins
+
+obexd_builtin_modules =
+obexd_builtin_sources =
+obexd_builtin_nodist =
+
+obexd_builtin_modules += filesystem
+obexd_builtin_sources += obexd/plugins/filesystem.c obexd/plugins/filesystem.h
+
+obexd_builtin_modules += bluetooth
+obexd_builtin_sources += obexd/plugins/bluetooth.c
+
+if EXPERIMENTAL
+obexd_builtin_modules += pcsuite
+obexd_builtin_sources += obexd/plugins/pcsuite.c
+endif
+
+obexd_builtin_modules += opp
+obexd_builtin_sources += obexd/plugins/opp.c
+
+obexd_builtin_modules += ftp
+obexd_builtin_sources += obexd/plugins/ftp.c obexd/plugins/ftp.h
+
+if OBEX
+obexd_builtin_modules += irmc
+obexd_builtin_sources += obexd/plugins/irmc.c
+
+obexd_builtin_modules += pbap
+obexd_builtin_sources += obexd/plugins/pbap.c \
+				obexd/plugins/vcard.h obexd/plugins/vcard.c \
+				obexd/plugins/phonebook.h \
+				obexd/plugins/phonebook-dummy.c
+endif
+
+obexd_builtin_modules += mas
+obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \
+				obexd/plugins/messages.h \
+				obexd/plugins/messages-dummy.c
+
+obexd_builtin_modules += mns
+obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
+				obexd/client/map-event.h
+
+libexec_PROGRAMS += obexd/src/obexd
+
+obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
+			$(obexd_builtin_sources) \
+			obexd/src/main.c obexd/src/obexd.h \
+			obexd/src/plugin.h obexd/src/plugin.c \
+			obexd/src/log.h obexd/src/log.c \
+			obexd/src/manager.h obexd/src/manager.c \
+			obexd/src/obex.h obexd/src/obex.c obexd/src/obex-priv.h \
+			obexd/src/mimetype.h obexd/src/mimetype.c \
+			obexd/src/service.h obexd/src/service.c \
+			obexd/src/transport.h obexd/src/transport.c \
+			obexd/src/server.h obexd/src/server.c \
+			obexd/client/manager.h obexd/client/manager.c \
+			obexd/client/session.h obexd/client/session.c \
+			obexd/client/bluetooth.h obexd/client/bluetooth.c \
+			obexd/client/sync.h obexd/client/sync.c \
+			obexd/client/pbap.h obexd/client/pbap.c \
+			obexd/client/ftp.h obexd/client/ftp.c \
+			obexd/client/opp.h obexd/client/opp.c \
+			obexd/client/map.h obexd/client/map.c \
+			obexd/client/map-event.h obexd/client/map-event.c \
+			obexd/client/transfer.h obexd/client/transfer.c \
+			obexd/client/transport.h obexd/client/transport.c \
+			obexd/client/dbus.h obexd/client/dbus.c \
+			obexd/client/driver.h obexd/client/driver.c \
+			obexd/src/map_ap.h
+obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
+			gdbus/libgdbus-internal.la \
+			@ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
+
+obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
+
+obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
+				@ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \
+				-DPLUGINDIR=\""$(obex_plugindir)"\" \
+				-fPIC -D_FILE_OFFSET_BITS=64
+
+obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src
+
+obexd_src_obexd_SHORTNAME = obexd
+
+obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist)
+
+nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files)
+
+BUILT_SOURCES += obexd/src/builtin.h
+
+obexd/src/plugin.$(OBJEXT): obexd/src/builtin.h
+
+obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources)
+	$(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@
+
+CLEANFILES += obexd/src/builtin.h $(builtin_files) obexd/src/obex.service
+
+EXTRA_DIST += obexd/src/genbuiltin
diff --git a/repo/Makefile.plugins b/repo/Makefile.plugins
new file mode 100644
index 0000000..f85b642
--- /dev/null
+++ b/repo/Makefile.plugins
@@ -0,0 +1,125 @@
+
+builtin_modules += hostname
+builtin_sources += plugins/hostname.c
+
+builtin_modules += wiimote
+builtin_sources += plugins/wiimote.c
+
+builtin_modules += autopair
+builtin_sources += plugins/autopair.c
+
+builtin_modules += policy
+builtin_sources += plugins/policy.c
+
+if MAINTAINER_MODE
+builtin_modules += gatt_example
+builtin_sources += plugins/gatt-example.c
+endif
+
+if EXPERIMENTAL
+builtin_modules += neard
+builtin_sources += plugins/neard.c
+
+builtin_modules += sap
+builtin_sources += profiles/sap/main.c profiles/sap/manager.h \
+			profiles/sap/manager.c profiles/sap/server.h \
+			profiles/sap/server.c profiles/sap/sap.h \
+			profiles/sap/sap-dummy.c
+
+noinst_LIBRARIES += profiles/sap/libsap.a
+profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
+endif
+
+builtin_modules += a2dp
+builtin_sources += profiles/audio/source.h profiles/audio/source.c \
+			profiles/audio/sink.h profiles/audio/sink.c \
+			profiles/audio/a2dp.h profiles/audio/a2dp.c \
+			profiles/audio/avdtp.h profiles/audio/avdtp.c \
+			profiles/audio/media.h profiles/audio/media.c \
+			profiles/audio/transport.h profiles/audio/transport.c \
+			profiles/audio/a2dp-codecs.h
+
+builtin_modules += avrcp
+builtin_sources += profiles/audio/control.h profiles/audio/control.c \
+			profiles/audio/avctp.h profiles/audio/avctp.c \
+			profiles/audio/avrcp.h profiles/audio/avrcp.c \
+			profiles/audio/player.h profiles/audio/player.c
+
+builtin_modules += network
+builtin_sources += profiles/network/manager.c \
+			profiles/network/bnep.h profiles/network/bnep.c \
+			profiles/network/server.h profiles/network/server.c \
+			profiles/network/connection.h \
+			profiles/network/connection.c
+
+builtin_modules += input
+builtin_sources += profiles/input/manager.c \
+			profiles/input/server.h profiles/input/server.c \
+			profiles/input/device.h profiles/input/device.c \
+			profiles/input/hidp_defs.h
+
+builtin_modules += hog
+builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \
+			profiles/input/hog-lib.c profiles/input/hog-lib.h \
+			profiles/deviceinfo/dis.c profiles/deviceinfo/dis.h \
+			profiles/battery/bas.c profiles/battery/bas.h \
+			profiles/scanparam/scpp.c profiles/scanparam/scpp.h \
+			profiles/input/suspend.h profiles/input/suspend-none.c
+
+EXTRA_DIST += profiles/input/suspend-dummy.c
+
+if EXPERIMENTAL
+builtin_modules += health
+builtin_sources += profiles/health/mcap.h profiles/health/mcap.c \
+			profiles/health/hdp_main.c profiles/health/hdp_types.h \
+			profiles/health/hdp_manager.h \
+			profiles/health/hdp_manager.c \
+			profiles/health/hdp.h profiles/health/hdp.c \
+			profiles/health/hdp_util.h profiles/health/hdp_util.c
+endif
+
+builtin_modules += gap
+builtin_sources += profiles/gap/gas.c
+
+builtin_modules += scanparam
+builtin_sources += profiles/scanparam/scan.c
+
+builtin_modules += deviceinfo
+builtin_sources += profiles/deviceinfo/deviceinfo.c
+
+if EXPERIMENTAL
+builtin_modules += alert
+builtin_sources += profiles/alert/server.c
+
+builtin_modules += time
+builtin_sources += profiles/time/server.c
+
+builtin_modules += proximity
+builtin_sources += profiles/proximity/main.c profiles/proximity/manager.h \
+			profiles/proximity/manager.c \
+			profiles/proximity/monitor.h \
+			profiles/proximity/monitor.c \
+			profiles/proximity/reporter.h \
+			profiles/proximity/reporter.c \
+			profiles/proximity/linkloss.h \
+			profiles/proximity/linkloss.c \
+			profiles/proximity/immalert.h \
+			profiles/proximity/immalert.c
+
+builtin_modules += thermometer
+builtin_sources += profiles/thermometer/thermometer.c
+
+builtin_modules += heartrate
+builtin_sources += profiles/heartrate/heartrate.c
+
+builtin_modules += cyclingspeed
+builtin_sources += profiles/cyclingspeed/cyclingspeed.c
+endif
+
+if SIXAXIS
+plugin_LTLIBRARIES += plugins/sixaxis.la
+plugins_sixaxis_la_SOURCES = plugins/sixaxis.c
+plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+						-no-undefined @UDEV_LIBS@
+plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden @UDEV_CFLAGS@
+endif
diff --git a/repo/Makefile.tools b/repo/Makefile.tools
new file mode 100644
index 0000000..e79b53b
--- /dev/null
+++ b/repo/Makefile.tools
@@ -0,0 +1,421 @@
+
+if CLIENT
+bin_PROGRAMS += client/bluetoothctl
+
+client_bluetoothctl_SOURCES = client/main.c \
+					client/display.h client/display.c \
+					client/agent.h client/agent.c \
+					client/gatt.h client/gatt.c \
+					monitor/uuid.h monitor/uuid.c
+client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
+				-lreadline
+endif
+
+if MONITOR
+bin_PROGRAMS += monitor/btmon
+
+monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
+				monitor/display.h monitor/display.c \
+				monitor/hcidump.h monitor/hcidump.c \
+				monitor/ellisys.h monitor/ellisys.c \
+				monitor/control.h monitor/control.c \
+				monitor/packet.h monitor/packet.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 \
+				monitor/l2cap.h monitor/l2cap.c \
+				monitor/sdp.h monitor/sdp.c \
+				monitor/avctp.h monitor/avctp.c \
+				monitor/avdtp.h monitor/avdtp.c \
+				monitor/a2dp.h monitor/a2dp.c \
+				monitor/rfcomm.h monitor/rfcomm.c \
+				monitor/bnep.h monitor/bnep.c \
+				monitor/uuid.h monitor/uuid.c \
+				monitor/hwdb.h monitor/hwdb.c \
+				monitor/keys.h monitor/keys.c \
+				monitor/analyze.h monitor/analyze.c \
+				monitor/intel.h monitor/intel.c \
+				monitor/broadcom.h monitor/broadcom.c
+monitor_btmon_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-mainloop.la @UDEV_LIBS@
+endif
+
+if EXPERIMENTAL
+noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \
+					peripheral/btsensor tools/3dsp \
+					tools/mgmt-tester tools/gap-tester \
+					tools/l2cap-tester tools/sco-tester \
+					tools/smp-tester tools/hci-tester \
+					tools/rfcomm-tester tools/bnep-tester \
+					tools/userchan-tester
+
+emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
+				emulator/serial.h emulator/serial.c \
+				emulator/server.h emulator/server.c \
+				emulator/vhci.h emulator/vhci.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c \
+				emulator/phy.h emulator/phy.c \
+				emulator/amp.h emulator/amp.c \
+				emulator/le.h emulator/le.c
+emulator_btvirt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+emulator_b1ee_SOURCES = emulator/b1ee.c
+emulator_b1ee_LDADD = src/libshared-mainloop.la
+
+emulator_hfp_SOURCES = emulator/hfp.c
+emulator_hfp_LDADD = src/libshared-mainloop.la
+
+peripheral_btsensor_SOURCES = peripheral/main.c \
+				peripheral/efivars.h peripheral/efivars.c \
+				peripheral/attach.h peripheral/attach.c \
+				peripheral/log.h peripheral/log.c \
+				peripheral/gap.h peripheral/gap.c \
+				peripheral/gatt.h peripheral/gatt.c
+peripheral_btsensor_LDADD = src/libshared-mainloop.la \
+				lib/libbluetooth-internal.la
+
+tools_3dsp_SOURCES = tools/3dsp.c monitor/bt.h
+tools_3dsp_LDADD = src/libshared-mainloop.la
+
+tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_mgmt_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_bnep_tester_SOURCES = tools/bnep-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_bnep_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_smp_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_gap_tester_LDADD =  lib/libbluetooth-internal.la \
+				gdbus/libgdbus-internal.la \
+				src/libshared-glib.la \
+				@GLIB_LIBS@ @DBUS_LIBS@
+
+tools_sco_tester_SOURCES = tools/sco-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_sco_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
+tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+endif
+
+if TOOLS
+bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
+			tools/rfcomm tools/rctest tools/l2test tools/l2ping \
+			tools/sdptool tools/ciptool tools/bccmd \
+			tools/bluemoon tools/hex2hcd tools/mpris-proxy
+
+tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+						tools/hciattach_st.c \
+						tools/hciattach_ti.c \
+						tools/hciattach_tialt.c \
+						tools/hciattach_ath3k.c \
+						tools/hciattach_qualcomm.c \
+						tools/hciattach_intel.c \
+						tools/hciattach_bcm43xx.c
+tools_hciattach_LDADD = lib/libbluetooth-internal.la
+
+tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
+tools_hciconfig_LDADD = lib/libbluetooth-internal.la
+
+tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c
+tools_hcitool_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
+
+tools_hcidump_SOURCES = tools/hcidump.c \
+				tools/parser/parser.h tools/parser/parser.c \
+				tools/parser/lmp.c \
+				tools/parser/hci.c \
+				tools/parser/l2cap.h tools/parser/l2cap.c \
+				tools/parser/amp.c \
+				tools/parser/smp.c \
+				tools/parser/att.c \
+				tools/parser/sdp.h tools/parser/sdp.c \
+				tools/parser/rfcomm.h tools/parser/rfcomm.c \
+				tools/parser/bnep.c \
+				tools/parser/cmtp.c \
+				tools/parser/hidp.c \
+				tools/parser/hcrp.c \
+				tools/parser/avdtp.c \
+				tools/parser/avctp.c \
+				tools/parser/avrcp.c \
+				tools/parser/sap.c \
+				tools/parser/obex.c \
+				tools/parser/capi.c \
+				tools/parser/ppp.c \
+				tools/parser/tcpip.c \
+				tools/parser/ericsson.c \
+				tools/parser/csr.c \
+				tools/parser/bpa.c
+tools_hcidump_LDADD = lib/libbluetooth-internal.la
+
+tools_rfcomm_LDADD = lib/libbluetooth-internal.la
+
+tools_rctest_LDADD = lib/libbluetooth-internal.la
+
+tools_l2test_LDADD = lib/libbluetooth-internal.la
+
+tools_l2ping_LDADD = lib/libbluetooth-internal.la
+
+tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
+tools_sdptool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_ciptool_LDADD = lib/libbluetooth-internal.la
+
+tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
+			tools/csr_hci.c tools/csr_usb.c \
+			tools/csr_h4.c tools/csr_3wire.c \
+			tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+tools_bccmd_LDADD = lib/libbluetooth-internal.la
+
+tools_bluemoon_SOURCES = tools/bluemoon.c monitor/bt.h
+tools_bluemoon_LDADD = src/libshared-mainloop.la
+
+tools_hex2hcd_SOURCES = tools/hex2hcd.c
+
+tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
+tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+
+dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
+			tools/hcitool.1 tools/hcidump.1 \
+			tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+			tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+else
+EXTRA_DIST += tools/hciattach.1 tools/hciconfig.1 \
+			tools/hcitool.1 tools/hcidump.1 \
+			tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+			tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+endif
+
+if HID2HCI
+udevdir = @UDEV_DIR@
+
+udev_PROGRAMS = tools/hid2hci
+
+tools_hid2hci_LDADD = @UDEV_LIBS@
+
+dist_man_MANS += tools/hid2hci.1
+else
+EXTRA_DIST += tools/hid2hci.1
+endif
+
+if EXPERIMENTAL
+bin_PROGRAMS += tools/btattach
+
+noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
+			tools/scotest tools/amptest tools/hwdb \
+			tools/hcieventmask tools/hcisecfilter \
+			tools/btinfo \
+			tools/btsnoop tools/btproxy \
+			tools/btiotest tools/bneptest tools/mcaptest \
+			tools/cltest tools/oobtest tools/seq2bseq \
+			tools/nokfw tools/create-image \
+			tools/eddystone tools/ibeacon \
+			tools/btgatt-client tools/btgatt-server \
+			tools/test-runner tools/check-selftest
+
+tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
+tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
+
+tools_avinfo_LDADD = lib/libbluetooth-internal.la
+
+tools_avtest_LDADD = lib/libbluetooth-internal.la
+
+tools_scotest_LDADD = lib/libbluetooth-internal.la
+
+tools_amptest_LDADD = lib/libbluetooth-internal.la
+
+tools_hwdb_LDADD = lib/libbluetooth-internal.la
+
+tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
+
+tools_btinfo_SOURCES = tools/btinfo.c monitor/bt.h
+tools_btinfo_LDADD = src/libshared-mainloop.la
+
+tools_btattach_SOURCES = tools/btattach.c monitor/bt.h
+tools_btattach_LDADD = src/libshared-mainloop.la
+
+tools_btsnoop_SOURCES = tools/btsnoop.c
+tools_btsnoop_LDADD = src/libshared-mainloop.la
+
+tools_btproxy_SOURCES = tools/btproxy.c monitor/bt.h
+tools_btproxy_LDADD = src/libshared-mainloop.la
+
+tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
+tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_mcaptest_SOURCES = tools/mcaptest.c \
+				btio/btio.h btio/btio.c \
+				src/log.c src/log.h \
+				profiles/health/mcap.h profiles/health/mcap.c
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
+
+tools_bneptest_SOURCES = tools/bneptest.c \
+				btio/btio.h btio/btio.c \
+				src/log.h src/log.c \
+				profiles/network/bnep.h profiles/network/bnep.c
+tools_bneptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_cltest_SOURCES = tools/cltest.c
+tools_cltest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+tools_oobtest_SOURCES = tools/oobtest.c
+tools_oobtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+tools_seq2bseq_SOURCES = tools/seq2bseq.c
+
+tools_nokfw_SOURCES = tools/nokfw.c
+
+tools_create_image_SOURCES = tools/create-image.c
+
+tools_eddystone_SOURCES = tools/eddystone.c monitor/bt.h
+tools_eddystone_LDADD = src/libshared-mainloop.la
+
+tools_ibeacon_SOURCES = tools/ibeacon.c monitor/bt.h
+tools_ibeacon_LDADD = src/libshared-mainloop.la
+
+tools_btgatt_client_SOURCES = tools/btgatt-client.c src/uuid-helper.c
+tools_btgatt_client_LDADD = src/libshared-mainloop.la \
+						lib/libbluetooth-internal.la
+
+tools_btgatt_server_SOURCES = tools/btgatt-server.c src/uuid-helper.c
+tools_btgatt_server_LDADD = src/libshared-mainloop.la \
+						lib/libbluetooth-internal.la
+
+dist_man_MANS += tools/btattach.1
+
+EXTRA_DIST += tools/bdaddr.1
+else
+EXTRA_DIST += tools/btattach.1
+endif
+
+if READLINE
+noinst_PROGRAMS += attrib/gatttool tools/btmgmt \
+			tools/obex-client-tool tools/obex-server-tool \
+			tools/bluetooth-player tools/obexctl
+
+attrib_gatttool_SOURCES = 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 \
+				client/display.h
+attrib_gatttool_LDADD = lib/libbluetooth-internal.la \
+			src/libshared-glib.la @GLIB_LIBS@ -lreadline
+
+tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+						tools/obex-client-tool.c
+tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
+						@GLIB_LIBS@ -lreadline
+
+tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+						tools/obex-server-tool.c
+tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \
+				client/display.h client/display.c
+tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \
+				@GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_obexctl_SOURCES = tools/obexctl.c \
+				client/display.h client/display.c
+tools_obexctl_LDADD = gdbus/libgdbus-internal.la \
+				@GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \
+				-lreadline
+endif
+
+if EXPERIMENTAL
+noinst_PROGRAMS += tools/gatt-service
+
+tools_gatt_service_SOURCES = tools/gatt-service.c
+tools_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
+
+noinst_PROGRAMS += profiles/iap/iapd
+
+profiles_iap_iapd_SOURCES = profiles/iap/main.c
+profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+endif
+
+if CUPS
+cupsdir = $(libdir)/cups/backend
+
+cups_PROGRAMS = profiles/cups/bluetooth
+
+profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \
+					profiles/cups/cups.h \
+					profiles/cups/sdp.c \
+					profiles/cups/spp.c \
+					profiles/cups/hcrp.c
+
+profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+				lib/libbluetooth-internal.la \
+				gdbus/libgdbus-internal.la
+endif
+
+test_scripts += test/sap_client.py test/bluezutils.py \
+		test/dbusdef.py test/monitor-bluetooth test/list-devices \
+		test/test-discovery test/test-manager test/test-adapter \
+		test/test-device test/simple-agent \
+		test/simple-endpoint test/test-sap-server \
+		test/test-proximity test/test-network \
+		test/test-thermometer test/test-profile test/test-health \
+		test/test-health-sink test/service-record.dtd \
+		test/service-did.xml test/service-spp.xml test/service-opp.xml \
+		test/service-ftp.xml test/simple-player test/test-nap \
+		test/test-heartrate test/test-alert test/test-hfp \
+		test/test-cyclingspeed test/opp-client test/ftp-client \
+		test/pbap-client test/map-client test/example-advertisement \
+		test/example-gatt-server test/example-gatt-client \
+		test/test-gatt-profile
diff --git a/repo/NEWS b/repo/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/repo/NEWS
diff --git a/repo/README b/repo/README
new file mode 100644
index 0000000..c991ab0
--- /dev/null
+++ b/repo/README
@@ -0,0 +1,127 @@
+BlueZ - Bluetooth protocol stack for Linux
+******************************************
+
+Copyright (C) 2000-2001  Qualcomm Incorporated
+Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
+Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+
+
+Compilation and installation
+============================
+
+In order to compile Bluetooth utilities you need following software packages:
+	- GCC compiler
+	- GLib library
+	- D-Bus library
+	- udev library (optional)
+	- readline (command line clients)
+
+To configure run:
+	./configure --prefix=/usr --mandir=/usr/share/man \
+				--sysconfdir=/etc --localstatedir=/var
+
+Configure automatically searches for all required components and packages.
+
+To compile and install run:
+	make && make install
+
+
+Configuration and options
+=========================
+
+For a working system, certain configuration options need to be enabled:
+
+	--enable-library
+
+		Enable installation of Bluetooth library
+
+		By default the Bluetooth library is no longer installed.
+
+		The user interfaces or command line utilities do not
+		require an installed Bluetooth library anymore. This
+		option is provided for legacy third party applications
+		that still depend on the library.
+
+		When the library installation is enabled, it is a good
+		idea to use a separate bluez-library or libbluetooth
+		package for it.
+
+	--disable-tools
+
+		Disable support for Bluetooth utilities
+
+		By default the Bluetooth utilities are built and also
+		installed. For production systems the tools are not
+		needed and this option allows to disable them to save
+		build time and disk space.
+
+		When the tools are selected, it is a good idea to
+		use a separate bluez-tools package for them.
+
+	--disable-cups
+
+		Disable support for CUPS printer backend
+
+		By default the printer backend for CUPS is build and
+		also installed. For systems that do not require printing
+		over Bluetooth, this options allows to disable it.
+
+		When the CUPS backend is selected, it is a good idea to
+		use a separate bluez-cups package for it.
+
+	--disable-monitor
+
+		Disable support for the Bluetooth monitor utility
+
+		By default the monitor utility is enabled. It provides
+		support for HCI level tracing and debugging. For systems
+		that don't require any kind of tracing or debugging
+		capabilities, this options allows to disable it.
+
+		The monitor utility should be placed in the main package
+		along with the daemons. It is universally useful.
+
+	--disable-client
+
+		Disable support for the command line client
+
+		By default the command line client is enabled and uses the
+		readline library. For specific systems where BlueZ is
+		configured by other means, the command line client can be
+		disabled and the dependency on readline is removed.
+
+		The client should be placed in the main package along
+		with the daemons. It is universally useful.
+
+	--disable-systemd
+
+		Disable integration with systemd
+
+		By default the integration with systemd is enabled and
+		installed. This gives the best integration into all
+		distributions based on systemd.
+
+		This option is provided for distributions that do not
+		support systemd. In that case all integration with the
+		init system is up to the package.
+
+	--enable-experimental
+
+		Enable experimental plugins
+
+		By default all plugins that are still in development
+		are disabled. This option can be used to enable them.
+
+		It is not recommended to enable this option for production
+		systems. The APIs or behavior of the experimental plugins
+		is unstable and might still change.
+
+
+Information
+===========
+
+Mailing lists:
+	linux-bluetooth@vger.kernel.org
+
+For additional information about the project visit BlueZ web site:
+	http://www.bluez.org
diff --git a/repo/TODO b/repo/TODO
new file mode 100644
index 0000000..8c710ef
--- /dev/null
+++ b/repo/TODO
@@ -0,0 +1,288 @@
+Background
+==========
+
+- Priority scale: High, Medium and Low
+
+- Complexity scale: C1, C2, C4 and C8.  The complexity scale is exponential,
+  with complexity 1 being the lowest complexity.  Complexity is a function
+  of both task 'complexity' and task 'scope'.
+
+  The general rule of thumb is that a complexity 1 task should take 1-2 weeks
+  for a person very familiar with BlueZ codebase.  Higher complexity tasks
+  require more time and have higher uncertainty.
+
+  Higher complexity tasks should be refined into several lower complexity tasks
+  once the task is better understood.
+
+General
+=======
+
+- UUID handling: Use the new functions created for UUID handling in all parts
+  of BlueZ code.  Currently, the new bt_uuid_* functions are being used by
+  GATT-related code only.
+
+  Priority: high
+  Complexity: C4
+
+- Update PBAP client/server implementation to 1.2 and create necessary APIs for
+  new features it introduces.
+
+  Priority: Medium
+  Complexity: C4
+
+- Create GOEP unit tests based on its test specification:
+
+  https://www.bluetooth.org/docman/handlers/DownloadDoc.ashx?doc_id=230559
+
+  Priority: Medium
+  Complexity: C2
+
+- Function in src/adapter.c to convert old storage files to new ini-file format
+  should be removed 6-8 months after first BlueZ 5 release.
+
+  Priority: Low
+  Complexity: C1
+
+- Remove usage of symlinks for drivers, such as profiles/input/suspend.c and
+  profiles/sap/sap.c. Instead, select drivers at runtime by using config
+  options or probing for running D-Bus services (using e.g.
+  g_dbus_add_service_watch()). Idea first mentioned on
+  http://thread.gmane.org/gmane.linux.bluez.kernel/30175/focus=30190.
+
+- Reuse connection handling code of src/profile.c also for built-in profiles
+  so plugins would only need to register their btd_profile and the core takes
+  care of the rest including listen to the right channel and manages the sdp
+  record. Once btd_profile manages the connection it can also notify about
+  their state, this probably remove the need of having callbacks to
+  .connect/.disconnect since their state can be tracked, it also enables any
+  plugin to track any profile state change which can be useful for e.g.
+  a connection policy plugin in case one is needed.
+
+  Priority: Low
+  Complexity: C2
+
+- Add queueing support for src/agent.c, currently if there is any request
+  pending the code fail with error EBUSY which is very inconvenient.
+
+  Priority: Low
+  Complexity: C2
+
+Low Energy
+==========
+
+- Connection modes. Adapter interface needs to be changed to manage
+  connection modes and adapter type. See Volume 3, Part C, section 9.3.
+  1. Mode management: Peripheral / Central
+
+  Priority: Medium
+  Complexity: C2
+
+- Advertising data. The D-Bus interface needs to be updated to enable setting
+  scan response data, and to read the advertising and scan response data which
+  has been broadcast from other LE devices.
+
+  Priority: Medium
+  Complexity: C2
+
+- Static random address setup and storage. Once this address is written
+  in a given remote, the address can not be changed anymore.
+
+  Priority: Low
+  Complexity: C1
+
+- Device Name Characteristic is a GAP characteristic for Low Energy. This
+  characteristic shall be integrated/used in the discovery procedure. The
+  idea is to report the value of this characteristic using DeviceFound signals.
+  Discussion with the community is needed before to start this task. Other GAP
+  characteristics for LE needs to follow a similar approach. It is not clear
+  if all GAP characteristics can be exposed using properties instead of a primary
+  service characteristics.
+  See Volume 3, Part C, section 12.1 for more information.
+
+  Priority: Low
+  Complexity: C2
+
+ATT/GATT (new shared stack)
+===========================
+
+- Add complete GATT test coverage in unit/test-gatt following the GATT test
+  spec. This could use shared/gatt-client and shared/gatt-server at the same
+  time to test both against eachother. We should definitely have tests for
+  gatt-server and gatt-client simultaneously on one side of the connection.
+
+  Priority: High
+  Complexity: C4
+
+- Write an example using client D-Bus API using C.
+
+  Priority: High
+  Complexity: C2
+
+- Write an example using client D-Bus API using python.
+
+  Priority: High
+  Complexity: C2
+
+- Define packed structs for ATT protocol PDUs in shared/att-types to improve
+  readability. We should probably do this once there are extensive unit tests
+  for gatt-client/gatt-server so that we don't accidentally break working code.
+
+  Priority: Medium
+  Complexity: C2
+
+- Use struct iovec to pass around byte buffers that will be sent over the wire,
+  instead of passing uint8_t and size_t parameters everywhere.
+
+  Priority: Medium
+  Complexity: C1
+
+- Persist client attribute cache across reboots.
+
+  Priority: Medium
+  Complexity: C4
+
+- Move all daemon plugins and profiles that are GATT based to use
+  shared/gatt-client instead of attrib/*. This is a complicated task that
+  potentially needs a new plugin/profile probing interface and a lot of
+  rewriting that can cause regressions in existing functionality.
+
+  Priority: Medium
+  Complexity: C4
+
+- Introduce a way for shared/gatt-server to check security permissions on the
+  current connection through bt_att.
+
+  Priority: Medium
+  Complexity: C2
+
+- Implement other low-priority ATT protocol operations for shared/gatt-server:
+
+      Read Multiple Request
+
+  Priority: Low
+  Complexity: C1
+
+- Implement the server portion of doc/gatt-api.txt using shared/gatt-server once
+  it exists.
+
+  Priority: Medium
+  Complexity: C4
+
+- Send out indications from the "Service Changed" characteristic upon
+  reconnection if a bonded device is not connected when the local database is
+  modified.
+
+  Priority: High
+  Complexity: C2
+
+- Unify the GATT server and client D-Bus implementations into a single module.
+  While these don't share a lot of code, keeping them all in src/gatt-dbus seems
+  to make more sense from an organizational perspective.
+
+  Priority: Low
+  Complexity: C1
+
+- Isolate all GATT code inside the daemon into its own module and perform
+  interaction with other modules (e.g. src/device.c) via callbacks. This
+  includes client/server management, tracking incoming/outgoing connections for
+  ATT, and callbacks to perform profile probing.
+
+  Priority: Low
+  Complexity: C4
+
+- Support included services in the GATT D-Bus client API.
+
+  Priority: Medium
+  Complexity: C1
+
+- The recently added support for ATT signed writes requires the following kernel
+  modules to be enabled:
+
+     CONFIG_CRYPTO_USER_API
+     CONFIG_CRYPTO_USER_API_HASH
+     CONFIG_CRYPTO_USER_API_SKCIPHER
+
+  Currently, if these are not enabled, bt_att_new silently returns NULL. We
+  should handle this more gracefully by not supporting signed writes if we can't
+  initialize bt_crypto while succeeding bt_att initialization regardless.
+
+  This behavior should be documented in the README.
+
+  Priority: High
+  Complexity: C1
+
+
+ATT/GATT (old/outdated)
+=======================
+
+- At the moment authentication and authorization is not supported at the
+  same time, read/write requirements in the attribute server needs to
+  be extended. According to Bluetooth Specification a server shall check
+  authentication and authorization requirements before any other check is
+  performed.
+
+  Priority: Medium
+  Complexity: C1
+
+- Implement ATT PDU validation. Malformed PDUs can cause division by zero
+  when decoding PDUs. A proper error PDU should be returned for this case.
+  See decoding function in att.c file.
+
+  Priority: Medium
+  Complexity: C1
+
+- Refactor read_by_group() and read_by_type() in src/attrib-server.c
+  (they've grown simply too big). First step could be to move out the
+  long for-loops to new functions called e.g. get_groups() and get_types().
+
+  Priority: Low
+  Complexity: C1
+
+- Agent for characteristics: Agent interface should be extended to support
+  authorization per characteristic if the remote is not in the trusted list.
+
+  Priority: Low
+  Complexity: C1
+
+- gatttool should have the ability to wait for req responses before
+  quitting (some servers require a small sleep even with cmd's). Maybe a
+  --delay-exit or --timeout command line switch.
+
+  Priority: Low
+  Complexity: C1
+
+- Client needs to export a property in the Device Characteristic hierarchy
+  to manage characteristic value changes reports in the remote device.
+  Currently, Client Characteristic Configuration attribute is not exposed
+  as an object. The user needs to use gatttool to change the value of the
+  this attribute to receive notification/indications. Export this attribute
+  as a property is a proposal that needs further discussion.
+
+  Priority: Low
+  Complexity: C1
+
+- Attribute server should process queued GATT/ATT commands if the
+  client disconnects. The client can simply send a command and quit,
+  without wait for a response(ex: Write Command). For this scenario
+  that the client disconnects the link quickly the queued received
+  command is ignored.
+
+  Priority: Low
+  Complecity: C1
+
+- Implement Server characteristic Configuration support in the attribute
+  server to manage characteristic value broadcasting. There is a single
+  instance of the Server Characteristic Configuration for all clients.
+  See Volume 3, Part G, section 3.3.3.4 for more information.
+
+  Priority: Low
+  Complexity: C1
+
+- Long write is not implemented. Attribute server, client and command line
+  tool shall be changed to support this feature.
+
+  Priority: Low
+  Complexity: C2
+
+Management Interface
+====================
diff --git a/repo/acinclude.m4 b/repo/acinclude.m4
new file mode 100644
index 0000000..bc39c6d
--- /dev/null
+++ b/repo/acinclude.m4
@@ -0,0 +1,62 @@
+AC_DEFUN([AC_PROG_CC_PIE], [
+	AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [
+		echo 'void f(){}' > conftest.c
+		if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+			ac_cv_prog_cc_pie=yes
+		else
+			ac_cv_prog_cc_pie=no
+		fi
+		rm -rf conftest*
+	])
+])
+
+AC_DEFUN([COMPILER_FLAGS], [
+	with_cflags=""
+	if (test "$USE_MAINTAINER_MODE" = "yes"); then
+		with_cflags="$with_cflags -Wall -Werror -Wextra"
+		with_cflags="$with_cflags -Wno-unused-parameter"
+		with_cflags="$with_cflags -Wno-missing-field-initializers"
+		with_cflags="$with_cflags -Wdeclaration-after-statement"
+		with_cflags="$with_cflags -Wmissing-declarations"
+		with_cflags="$with_cflags -Wredundant-decls"
+		with_cflags="$with_cflags -Wcast-align"
+		with_cflags="$with_cflags -Wswitch-enum"
+		with_cflags="$with_cflags -Wformat -Wformat-security"
+		with_cflags="$with_cflags -DG_DISABLE_DEPRECATED"
+		with_cflags="$with_cflags -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_28"
+		with_cflags="$with_cflags -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_28"
+	fi
+	AC_SUBST([WARNING_CFLAGS], $with_cflags)
+])
+
+AC_DEFUN([MISC_FLAGS], [
+	misc_cflags=""
+	misc_ldflags=""
+	AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
+			[disable code optimization through compiler]), [
+		if (test "${enableval}" = "no"); then
+			misc_cflags="$misc_cflags -O0"
+		fi
+	])
+	AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
+			[enable compiling with debugging information]), [
+		if (test "${enableval}" = "yes" &&
+				test "${ac_cv_prog_cc_g}" = "yes"); then
+			misc_cflags="$misc_cflags -g"
+		fi
+	])
+	AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
+			[enable position independent executables flag]), [
+		if (test "${enableval}" = "yes" &&
+				test "${ac_cv_prog_cc_pie}" = "yes"); then
+			misc_cflags="$misc_cflags -fPIC"
+			misc_ldflags="$misc_ldflags -pie"
+		fi
+	])
+	if (test "$enable_coverage" = "yes"); then
+		misc_cflags="$misc_cflags --coverage"
+		misc_ldflags="$misc_ldflags --coverage"
+	fi
+	AC_SUBST([MISC_CFLAGS], $misc_cflags)
+	AC_SUBST([MISC_LDFLAGS], $misc_ldflags)
+])
diff --git a/repo/android/Android.mk b/repo/android/Android.mk
new file mode 100644
index 0000000..38ef4aa
--- /dev/null
+++ b/repo/android/Android.mk
@@ -0,0 +1,855 @@
+LOCAL_PATH := external/bluetooth
+
+# Retrieve BlueZ version from configure.ac file
+BLUEZ_VERSION := `grep "^AC_INIT" $(LOCAL_PATH)/bluez/configure.ac | sed -e "s/.*,.\(.*\))/\1/"`
+
+ANDROID_VERSION := $(shell echo $(PLATFORM_VERSION) | awk -F. '{ printf "0x%02d%02d%02d",$$1,$$2,$$3 }')
+
+ANDROID_GE_5_0_0 := $(shell test `echo $$(($(ANDROID_VERSION)))` -lt `echo $$((0x050000))`; echo $$?)
+
+# Specify pathmap for glib and sbc
+pathmap_INCL += glib:external/bluetooth/glib \
+		sbc:external/bluetooth/sbc \
+
+# Specify common compiler flags
+BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
+			-DANDROID_VERSION=$(ANDROID_VERSION) \
+			-DANDROID_STORAGEDIR=\"/data/misc/bluetooth\" \
+			-DHAVE_LINUX_IF_ALG_H \
+			-DHAVE_LINUX_TYPES_H \
+
+# Enable warnings enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wall -Wextra \
+			-Wdeclaration-after-statement \
+			-Wmissing-declarations \
+			-Wredundant-decls \
+			-Wcast-align \
+
+# Disable warnings enabled by Android but not enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wno-pointer-arith \
+			-Wno-missing-field-initializers \
+			-Wno-unused-parameter \
+
+#
+# Android BlueZ daemon (bluetoothd)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/main.c \
+	bluez/android/bluetooth.c \
+	bluez/profiles/scanparam/scpp.c \
+	bluez/profiles/deviceinfo/dis.c \
+	bluez/profiles/battery/bas.c \
+	bluez/profiles/input/hog-lib.c \
+	bluez/android/hidhost.c \
+	bluez/android/socket.c \
+	bluez/android/ipc.c \
+	bluez/android/avdtp.c \
+	bluez/android/a2dp.c \
+	bluez/android/a2dp-sink.c \
+	bluez/android/avctp.c \
+	bluez/android/avrcp.c \
+	bluez/android/avrcp-lib.c \
+	bluez/android/pan.c \
+	bluez/android/handsfree.c \
+	bluez/android/handsfree-client.c \
+	bluez/android/gatt.c \
+	bluez/android/health.c \
+	bluez/android/sco.c \
+	bluez/profiles/health/mcap.c \
+	bluez/android/map-client.c \
+	bluez/android/log.c \
+	bluez/src/shared/mgmt.c \
+	bluez/src/shared/util.c \
+	bluez/src/shared/queue.c \
+	bluez/src/shared/ringbuf.c \
+	bluez/src/shared/hfp.c \
+	bluez/src/shared/gatt-db.c \
+	bluez/src/shared/io-glib.c \
+	bluez/src/shared/timeout-glib.c \
+	bluez/src/shared/crypto.c \
+	bluez/src/shared/uhid.c \
+	bluez/src/shared/att.c \
+	bluez/src/sdpd-database.c \
+	bluez/src/sdpd-service.c \
+	bluez/src/sdpd-request.c \
+	bluez/src/sdpd-server.c \
+	bluez/src/uuid-helper.c \
+	bluez/src/eir.c \
+	bluez/lib/sdp.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/lib/uuid.c \
+	bluez/btio/btio.c \
+	bluez/src/sdp-client.c \
+	bluez/profiles/network/bnep.c \
+	bluez/attrib/gattrib.c \
+	bluez/attrib/gatt.c \
+	bluez/attrib/att.c
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_TAGS := optional
+
+# for userdebug/eng this module is bluetoothd-main since bluetoothd is used as
+# wrapper to launch bluetooth with Valgrind
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_MODULE := bluetoothd-main
+LOCAL_STRIP_MODULE := false
+else
+LOCAL_MODULE := bluetoothd
+endif
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bluetooth.default.so HAL
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/hal-ipc.c \
+	bluez/android/hal-bluetooth.c \
+	bluez/android/hal-socket.c \
+	bluez/android/hal-hidhost.c \
+	bluez/android/hal-pan.c \
+	bluez/android/hal-a2dp.c \
+	bluez/android/hal-avrcp.c \
+	bluez/android/hal-handsfree.c \
+	bluez/android/hal-gatt.c \
+	bluez/android/hal-utils.c \
+	bluez/android/hal-health.c \
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_SRC_FILES += \
+	bluez/android/hal-handsfree-client.c \
+	bluez/android/hal-map-client.c \
+	bluez/android/hal-a2dp-sink.c \
+	bluez/android/hal-avrcp-ctrl.c
+endif
+
+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_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_REQUIRED_MODULES := bluetoothd bluetoothd-snoop init.bluetooth.rc
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# haltest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/client/haltest.c \
+	bluez/android/client/pollhandler.c \
+	bluez/android/client/terminal.c \
+	bluez/android/client/history.c \
+	bluez/android/client/tabcompletion.c \
+	bluez/android/client/if-audio.c \
+	bluez/android/client/if-sco.c \
+	bluez/android/client/if-av.c \
+	bluez/android/client/if-rc.c \
+	bluez/android/client/if-bt.c \
+	bluez/android/client/if-hf.c \
+	bluez/android/client/if-hh.c \
+	bluez/android/client/if-pan.c \
+	bluez/android/client/if-hl.c \
+	bluez/android/client/if-sock.c \
+	bluez/android/client/if-gatt.c \
+	bluez/android/hal-utils.c \
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_SRC_FILES += \
+	bluez/android/client/if-hf-client.c \
+	bluez/android/client/if-mce.c \
+	bluez/android/client/if-av-sink.c \
+	bluez/android/client/if-rc-ctrl.c
+endif
+
+LOCAL_C_INCLUDES += \
+	$(call include-path-for, system-core) \
+	$(call include-path-for, libhardware) \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez/android \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+
+LOCAL_SHARED_LIBRARIES := \
+	libhardware \
+	libcutils \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := haltest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# mcaptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/src/log.c \
+	bluez/btio/btio.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/profiles/health/mcap.c \
+	bluez/tools/mcaptest.c \
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := mcaptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bneptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/src/log.c \
+	bluez/btio/btio.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/profiles/network/bnep.c \
+	bluez/tools/bneptest.c \
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := bneptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# avdtptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/avdtptest.c \
+	bluez/android/avdtp.c \
+	bluez/src/log.c \
+	bluez/btio/btio.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/src/shared/util.c \
+	bluez/src/shared/queue.c \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avdtptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# btmon
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/monitor/main.c \
+	bluez/monitor/display.c \
+	bluez/monitor/hcidump.c \
+	bluez/monitor/control.c \
+	bluez/monitor/packet.c \
+	bluez/monitor/l2cap.c \
+	bluez/monitor/avctp.c \
+	bluez/monitor/avdtp.c \
+	bluez/monitor/a2dp.c \
+	bluez/monitor/rfcomm.c \
+	bluez/monitor/bnep.c \
+	bluez/monitor/uuid.c \
+	bluez/monitor/sdp.c \
+	bluez/monitor/vendor.c \
+	bluez/monitor/lmp.c \
+	bluez/monitor/crc.c \
+	bluez/monitor/ll.c \
+	bluez/monitor/hwdb.c \
+	bluez/monitor/keys.c \
+	bluez/monitor/ellisys.c \
+	bluez/monitor/analyze.c \
+	bluez/monitor/intel.c \
+	bluez/monitor/broadcom.c \
+	bluez/src/shared/util.c \
+	bluez/src/shared/queue.c \
+	bluez/src/shared/crypto.c \
+	bluez/src/shared/btsnoop.c \
+	bluez/src/shared/mainloop.c \
+	bluez/lib/hci.c \
+	bluez/lib/bluetooth.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btmon
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# btproxy
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/btproxy.c \
+	bluez/src/shared/mainloop.c \
+	bluez/src/shared/util.c \
+	bluez/src/shared/ecc.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btproxy
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# A2DP audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/hal-audio.c \
+	bluez/android/hal-audio-sbc.c \
+	bluez/android/hal-audio-aptx.c \
+
+LOCAL_C_INCLUDES = \
+	$(LOCAL_PATH)/bluez \
+	$(call include-path-for, system-core) \
+	$(call include-path-for, libhardware) \
+	$(call include-path-for, sbc) \
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libsbc \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+LOCAL_LDFLAGS := -ldl
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.a2dp.default
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# SCO audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bluez/android/hal-sco.c \
+	bluez/android/hal-utils.c
+
+LOCAL_C_INCLUDES = \
+	$(call include-path-for, system-core) \
+	$(call include-path-for, libhardware) \
+	$(call include-path-for, audio-utils) \
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libaudioutils \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.sco.default
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# l2cap-test
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/l2test.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := l2test
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bluetoothd-snoop
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/bluetoothd-snoop.c \
+	bluez/src/shared/mainloop.c \
+	bluez/src/shared/btsnoop.c \
+	bluez/android/log.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+	$(LOCAL_PATH)/bluez/lib \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothd-snoop
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# init.bluetooth.rc
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init.bluetooth.rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := bluez/android/$(LOCAL_MODULE)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+
+include $(BUILD_PREBUILT)
+
+#
+# btmgmt
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/btmgmt.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/lib/sdp.c \
+	bluez/src/shared/mainloop.c \
+	bluez/src/shared/io-mainloop.c \
+	bluez/src/shared/mgmt.c \
+	bluez/src/shared/queue.c \
+	bluez/src/shared/util.c \
+	bluez/src/shared/gap.c \
+	bluez/src/uuid-helper.c \
+	bluez/client/display.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+	$(LOCAL_PATH)/bluez/android/compat \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btmgmt
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hcitool
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/hcitool.c \
+	bluez/src/oui.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := hcitool
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hciconfig
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	bluez/tools/hciconfig.c \
+	bluez/tools/csr.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := hciconfig
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# l2ping
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/l2ping.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := l2ping
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# avtest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/avtest.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avtest
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hciattach
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/hciattach.c \
+	bluez/tools/hciattach_st.c \
+	bluez/tools/hciattach_ti.c \
+	bluez/tools/hciattach_tialt.c \
+	bluez/tools/hciattach_ath3k.c \
+	bluez/tools/hciattach_qualcomm.c \
+	bluez/tools/hciattach_intel.c \
+	bluez/tools/hciattach_bcm43xx.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := hciattach
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# libsbc
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	sbc/sbc/sbc.c \
+	sbc/sbc/sbc_primitives.c \
+	sbc/sbc/sbc_primitives_mmx.c \
+	sbc/sbc/sbc_primitives_neon.c \
+	sbc/sbc/sbc_primitives_armv6.c \
+	sbc/sbc/sbc_primitives_iwmmxt.c \
+
+LOCAL_C_INCLUDES:= \
+	$(LOCAL_PATH)/sbc \
+
+LOCAL_CFLAGS:= \
+	-Os \
+	-Wno-sign-compare \
+	-Wno-missing-field-initializers \
+	-Wno-unused-parameter \
+	-Wno-type-limits \
+	-Wno-empty-body \
+
+LOCAL_MODULE := libsbc
+
+include $(BUILD_SHARED_LIBRARY)
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+
+#
+# bluetoothd (debug)
+# this is just a wrapper used in userdebug/eng to launch bluetoothd-main
+# with/without Valgrind
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/bluetoothd-wrapper.c \
+	bluez/android/hal-utils.c
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothd
+
+LOCAL_REQUIRED_MODULES := \
+	bluetoothd-main \
+	valgrind \
+	memcheck-$(TARGET_ARCH)-linux \
+	vgpreload_core-$(TARGET_ARCH)-linux \
+	vgpreload_memcheck-$(TARGET_ARCH)-linux \
+	default.supp
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+#
+# bluetooth-headers
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bluetooth-headers
+LOCAL_NODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+include_path := $(local-intermediates-dir)/include
+include_files := $(wildcard $(LOCAL_PATH)/bluez/lib/*.h)
+$(shell mkdir -p $(include_path)/bluetooth)
+$(foreach file,$(include_files),$(shell cp -u $(file) $(include_path)/bluetooth))
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(include_path)
+
+include $(BUILD_STATIC_LIBRARY)
+
+#
+# avtest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/avinfo.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avinfo
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# rctest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/tools/rctest.c \
+	bluez/lib/bluetooth.c \
+	bluez/lib/hci.c \
+	bluez/lib/sdp.c \
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+	bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := rctest
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
diff --git a/repo/android/Makefile.am b/repo/android/Makefile.am
new file mode 100644
index 0000000..154f8db
--- /dev/null
+++ b/repo/android/Makefile.am
@@ -0,0 +1,320 @@
+if ANDROID
+
+AM_CFLAGS += -DANDROID_VERSION=0x050100
+
+android_plugindir = $(abs_top_srcdir)/android/.libs
+
+noinst_PROGRAMS += android/system-emulator
+
+android_system_emulator_SOURCES = android/system-emulator.c
+android_system_emulator_LDADD = src/libshared-mainloop.la
+
+noinst_PROGRAMS += android/bluetoothd-snoop
+
+android_bluetoothd_snoop_SOURCES = android/bluetoothd-snoop.c src/log.c
+android_bluetoothd_snoop_LDADD = src/libshared-mainloop.la @GLIB_LIBS@
+
+noinst_PROGRAMS += android/bluetoothd
+
+android_bluetoothd_SOURCES = android/main.c \
+				src/log.c \
+				android/hal-msg.h \
+				android/audio-msg.h \
+				android/sco-msg.h \
+				android/utils.h \
+				src/sdpd-database.c src/sdpd-server.c \
+				src/sdpd-service.c src/sdpd-request.c \
+				src/uuid-helper.h src/uuid-helper.c \
+				src/eir.h src/eir.c \
+				android/bluetooth.h android/bluetooth.c \
+				android/hidhost.h android/hidhost.c \
+				profiles/scanparam/scpp.h \
+				profiles/scanparam/scpp.c \
+				profiles/deviceinfo/dis.h \
+				profiles/deviceinfo/dis.c \
+				profiles/battery/bas.h profiles/battery/bas.c \
+				profiles/input/hog-lib.h \
+				profiles/input/hog-lib.c \
+				android/ipc-common.h \
+				android/ipc.h android/ipc.c \
+				android/avdtp.h android/avdtp.c \
+				android/a2dp.h android/a2dp.c \
+				android/a2dp-sink.h android/a2dp-sink.c \
+				android/avctp.h android/avctp.c \
+				android/avrcp.h android/avrcp.c \
+				android/avrcp-lib.h android/avrcp-lib.c \
+				android/socket.h android/socket.c \
+				android/sco.h android/sco.c \
+				android/pan.h android/pan.c \
+				android/handsfree.h android/handsfree.c \
+				android/handsfree-client.c android/handsfree-client.h \
+				android/gatt.h android/gatt.c \
+				android/health.h android/health.c \
+				profiles/health/mcap.h profiles/health/mcap.c \
+				android/map-client.h android/map-client.c \
+				attrib/att.c attrib/att.h \
+				attrib/gatt.c attrib/gatt.h \
+				attrib/gattrib.c attrib/gattrib.h \
+				btio/btio.h btio/btio.c \
+				src/sdp-client.h src/sdp-client.c \
+				profiles/network/bnep.h profiles/network/bnep.c
+android_bluetoothd_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+plugin_LTLIBRARIES += android/bluetooth.default.la
+
+android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
+					android/hal-socket.c \
+					android/hal-hidhost.c \
+					android/hal-health.c \
+					android/hal-pan.c \
+					android/hal-a2dp.c \
+					android/hal-a2dp-sink.c \
+					android/hal-avrcp.c \
+					android/hal-avrcp-ctrl.c \
+					android/hal-handsfree.c \
+					android/hal-handsfree-client.c \
+					android/hal-gatt.c \
+					android/hal-map-client.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/bt_hf_client.h \
+					android/hardware/bt_mce.h \
+					android/hardware/hardware.h \
+					android/cutils/properties.h \
+					android/ipc-common.h \
+					android/hal-log.h \
+					android/hal-ipc.h android/hal-ipc.c \
+					android/hal-utils.h android/hal-utils.c
+android_bluetooth_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_bluetooth_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+					-no-undefined
+
+noinst_PROGRAMS += android/avdtptest
+
+android_avdtptest_SOURCES = android/avdtptest.c \
+				src/log.h src/log.c \
+				btio/btio.h btio/btio.c \
+				src/shared/util.h src/shared/util.c \
+				src/shared/queue.h src/shared/queue.c \
+				android/avdtp.h android/avdtp.c
+android_avdtptest_CFLAGS = $(AM_CFLAGS)
+android_avdtptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+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-av-sink.c \
+				android/client/if-rc.c \
+				android/client/if-rc-ctrl.c \
+				android/client/if-bt.c \
+				android/client/if-gatt.c \
+				android/client/if-hf.c \
+				android/client/if-hf-client.c \
+				android/client/if-hh.c \
+				android/client/if-pan.c \
+				android/client/if-hl.c \
+				android/client/if-sock.c \
+				android/client/if-audio.c \
+				android/client/if-sco.c \
+				android/client/if-mce.c \
+				android/hardware/hardware.c \
+				android/hal-utils.h android/hal-utils.c
+android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+				-DPLUGINDIR=\""$(android_plugindir)"\"
+android_haltest_LDFLAGS = -pthread -ldl -lm
+
+noinst_PROGRAMS += android/android-tester
+
+android_android_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c \
+				monitor/rfcomm.h \
+				android/hardware/hardware.c \
+				android/tester-bluetooth.c \
+				android/tester-socket.c \
+				android/tester-hidhost.c \
+				android/tester-pan.c \
+				android/tester-hdp.c \
+				android/tester-a2dp.c \
+				android/tester-avrcp.c \
+				android/tester-gatt.c \
+				android/tester-map-client.c \
+				android/tester-main.h android/tester-main.c
+android_android_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+				-DPLUGINDIR=\""$(android_plugindir)"\"
+android_android_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+android_android_tester_LDFLAGS = -pthread -ldl
+
+noinst_PROGRAMS += android/ipc-tester
+
+android_ipc_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c \
+				android/hal-utils.h android/hal-utils.c \
+				android/ipc-common.h android/ipc-tester.c
+android_ipc_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_ipc_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la @GLIB_LIBS@
+
+plugin_LTLIBRARIES += android/audio.a2dp.default.la
+
+android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
+					android/hal-msg.h \
+					android/hal-audio.h \
+					android/hal-audio.c \
+					android/hal-audio-sbc.c \
+					android/hal-audio-aptx.c \
+					android/hardware/audio.h \
+					android/hardware/audio_effect.h \
+					android/hardware/hardware.h \
+					android/system/audio.h
+android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+					@SBC_CFLAGS@
+android_audio_a2dp_default_la_LIBADD = @SBC_LIBS@
+android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+					-no-undefined -pthread -lrt
+
+plugin_LTLIBRARIES += android/audio.sco.default.la
+
+android_audio_sco_default_la_SOURCES = android/hal-log.h \
+					android/sco-msg.h \
+					android/hal-sco.c \
+					android/hardware/audio.h \
+					android/hardware/audio_effect.h \
+					android/hardware/hardware.h \
+					android/audio_utils/resampler.c \
+					android/audio_utils/resampler.h \
+					android/system/audio.h
+android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_audio_sco_default_la_LIBADD = @SPEEXDSP_LIBS@
+android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+					-no-undefined -lrt
+unit_tests += android/test-ipc
+
+android_test_ipc_SOURCES = android/test-ipc.c \
+				src/log.h src/log.c \
+				android/ipc-common.h \
+				android/ipc.c android/ipc.h
+android_test_ipc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+endif
+
+EXTRA_DIST += android/Android.mk android/README \
+				android/compat/readline/history.h \
+				android/compat/readline/readline.h \
+				android/compat/wordexp.h \
+				android/bluetoothd-wrapper.c \
+				android/log.c \
+				android/bluetoothd.te \
+				android/bluetoothd_snoop.te \
+				android/init.bluetooth.rc \
+				android/hal-ipc-api.txt \
+				android/audio-ipc-api.txt \
+				android/cts.txt \
+				android/pics-rfcomm.txt \
+				android/pics-spp.txt \
+				android/pics-sdp.txt \
+				android/pics-l2cap.txt \
+				android/pics-gap.txt \
+				android/pics-did.txt \
+				android/pics-hid.txt \
+				android/pics-pan.txt \
+				android/pics-opp.txt \
+				android/pics-map.txt \
+				android/pics-pbap.txt \
+				android/pics-a2dp.txt \
+				android/pics-avctp.txt \
+				android/pics-avrcp.txt \
+				android/pics-hsp.txt \
+				android/pics-hfp.txt \
+				android/pics-gatt.txt \
+				android/pics-mcap.txt \
+				android/pics-hdp.txt \
+				android/pics-iopt.txt \
+				android/pics-sm.txt \
+				android/pics-mps.txt \
+				android/pics-hogp.txt \
+				android/pics-scpp.txt \
+				android/pics-dis.txt \
+				android/pics-avdtp.txt \
+				android/pics-gavdp.txt \
+				android/pics-bnep.txt \
+				android/pixit-l2cap.txt \
+				android/pixit-gap.txt \
+				android/pixit-did.txt \
+				android/pixit-hid.txt \
+				android/pixit-pan.txt \
+				android/pixit-opp.txt \
+				android/pixit-map.txt \
+				android/pixit-pbap.txt \
+				android/pixit-a2dp.txt \
+				android/pixit-avctp.txt \
+				android/pixit-avrcp.txt \
+				android/pixit-hsp.txt \
+				android/pixit-hfp.txt \
+				android/pixit-gatt.txt \
+				android/pixit-mcap.txt \
+				android/pixit-hdp.txt \
+				android/pixit-iopt.txt \
+				android/pixit-sm.txt \
+				android/pixit-mps.txt \
+				android/pixit-hogp.txt \
+				android/pixit-scpp.txt \
+				android/pixit-dis.txt \
+				android/pixit-rfcomm.txt \
+				android/pixit-spp.txt \
+				android/pixit-avdtp.txt \
+				android/pixit-gavdp.txt \
+				android/pixit-sdp.txt \
+				android/pixit-bnep.txt \
+				android/pts-rfcomm.txt \
+				android/pts-spp.txt \
+				android/pts-l2cap.txt \
+				android/pts-gap.txt \
+				android/pts-did.txt \
+				android/pts-hid.txt \
+				android/pts-pan.txt \
+				android/pts-opp.txt \
+				android/pts-map.txt \
+				android/pts-a2dp.txt \
+				android/pts-avrcp.txt \
+				android/pts-avctp.txt \
+				android/pts-pbap.txt \
+				android/pts-hfp.txt \
+				android/pts-gatt.txt \
+				android/pts-hsp.txt \
+				android/pts-iopt.txt \
+				android/pts-hdp.txt \
+				android/pts-mcap.txt \
+				android/pts-mps.txt \
+				android/pts-sm.txt \
+				android/pts-hogp.txt \
+				android/pts-scpp.txt \
+				android/pts-dis.txt \
+				android/pts-avdtp.txt \
+				android/pts-gavdp.txt \
+				android/pts-sdp.txt \
+				android/pts-bnep.txt
diff --git a/repo/android/README b/repo/android/README
new file mode 100644
index 0000000..fa4c42a
--- /dev/null
+++ b/repo/android/README
@@ -0,0 +1,454 @@
+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-ipc-api.txt file.
+
+Supported Android version: 4.4 KitKat and 5.0, 5.1 Lollipop
+
+
+Building and running on Android
+===============================
+
+Steps needed to build and run Android Open Source Project with integrated BlueZ.
+
+
+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://github.com/bluez-android/glib
+
+- SBC - A2DP code requires SBC library (version 1.2 or higher) present in
+'external/bluetooth/sbc' directory. Library is build from Android.mk provided
+by BlueZ. SBC code is available at git://git.kernel.org/pub/scm/bluetooth/sbc
+
+- Bionic support - Android 5.0 provides all required functionality. Running
+BlueZ on Android 4.4 requires backporting missing features (epoll_create1 and
+ppoll calls). Sample Bionic for Android 4.4 with all required features
+backported is available at
+https://github.com/bluez-android/aosp_platform_bionic
+
+Runtime requirements
+--------------------
+
+BlueZ HAL library requires 'bluetoothd' and 'bluetoothd-snoop' services to be
+available on Android system. Some permissions settings are also required.
+
+This can be done by importing init.bluetooth.rc file in init.rc file of targeted
+board:
+import init.bluetooth.rc
+
+For convenience examples are provided at:
+https://github.com/bluez-android/aosp_device_lge_mako           (Nexus 4)
+https://github.com/bluez-android/aosp_device_lge_hammerhead     (Nexus 5)
+https://github.com/bluez-android/aosp_device_asus_flo           (Nexus 7 2013)
+
+Security-Enhanced Linux in Android
+----------------------------------
+
+Since 5.0 release Android moved to full enforcement of SELinux. This requires
+proper policy to be provided for all BlueZ for Android services (and services
+interacting with BlueZ). Policies should be placed in external/selinux/ path.
+
+Required policy files are provided at:
+bluetoothd.te
+bluetoothd_snoop.te
+
+For convenience sepolicy.git with all required policies is available at:
+https://github.com/bluez-android/aosp_platform_external_sepolicy
+
+Downloading and building
+------------------------
+
+Building for Android requires full Android AOSP source tree. Sample Android tree
+with all required components present is available at
+https://github.com/bluez-android
+
+This tree provides support for Nexus4 (mako), Nexus 5 (hammerhead) and
+Nexus 7 2013 (flo, deb). Tree does not provide binary blobs needed to run
+Android on supported devices. Those can be obtained from
+https://developers.google.com/android/nexus/drivers. Binary blobs needs to be
+unpacked (EULA acceptance required) into 'vendor' directory of Android tree.
+
+Downloading:
+Android 5.0 - 'lollipop' branch
+Android 4.4 - 'kitkat' branch
+
+repo init -u https://github.com/bluez-android/aosp_platform_manifest \
+	-b lollipop
+repo sync
+
+Building:
+source build/envsetup.sh
+lunch aosp_<target>-userdebug
+make -j8
+
+Flashing:
+adb reboot bootloader
+fastboot flashall -w
+
+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.
+
+Downloading and building for Intel devices
+------------------------------------------
+
+Sample Android tree with all required components for Intel devices based on
+Intel reference image (https://01.org/android-ia) can be reconstructed following
+instructions below.
+
+This tree provides support for Dell XPS12, Minnowboard MAX, Intel NUC,
+Acer Iconia W700 and other devices mentioned in:
+https://01.org/android-ia/guides/devices
+
+Downloading:
+repo init -u https://github.com/01org/android-bluez-manifest.git -b android-ia \
+	-m topic/bluez
+repo sync
+
+Building:
+source build/envsetup.sh
+lunch haswell_generic-eng
+make -j8
+
+Installing:
+Live and Install image is $OUT/live.img
+Flash live.img to USB flash and boot from it. More instructions here:
+https://01.org/android-ia/guides/developers/build-and-install
+
+Linux Kernel requirements
+-------------------------
+
+BlueZ for Android uses Linux Bluetooth subsystem and it must be enabled in
+kernel. Minimal required version of management interface is 1.3. This
+corresponds to Linux 3.9 but latest available version is recommended. Other
+requirements include UHID and network bridge support.
+
+Following kernel options should be enabled:
+CONFIG_BT
+CONFIG_BT_RFCOMM
+CONFIG_BT_RFCOMM_TTY
+CONFIG_BT_BNEP
+CONFIG_BT_BNEP_MC_FILTER
+CONFIG_BT_BNEP_PROTO_FILTER
+CONFIG_BRIDGE
+CONFIG_UHID
+CONFIG_CRYPTO_CMAC
+CONFIG_CRYPTO_USER_API
+CONFIG_CRYPTO_USER_API_HASH
+CONFIG_CRYPTO_USER_API_SKCIPHER
+
+Also BT chip driver needs to be enabled e.g:
+CONFIG_BT_HCIBTUSB
+
+If it is not possible to use new enough Linux kernel one can use updated
+bluetooth subsystem from Backports project. More information about Backports can
+be found at https://backports.wiki.kernel.org. Sample kernels using backports
+for running BlueZ on Android are available at https://github.com/bluez-android.
+
+
+Running with Valgrind
+---------------------
+
+BlueZ for Android is preconfigured to be easily run under Valgrind memcheck.
+Appropriate configuration and required modules are automatically included when
+building either userdebug or eng variant of Android platform.
+
+Valgrind can be enabled in runtime by setting "persist.sys.bluetooth.valgrind"
+property to either literal "true" or any numeric value >0. For example:
+adb root
+adb shell setprop persist.sys.bluetooth.valgrind true
+
+After changing property value Bluetooth need to be restarted to apply changes
+(this can be done using UI, just disable and enable it again). Property is
+persistent, i.e. there's no need to enable Valgrind again after reboot.
+
+It's recommended to have unstripped libglib.so installed which will enable
+complete backtraces in Valgrind output. Otherwise, in many cases backtrace
+will break at e.g. g_free() function without prior callers. It's possible to
+have proper library installed automatically by appropriate entry in Android.mk,
+see https://github.com/bluez-android/glib for an example.
+
+When running with valgrind SElinux needs to be set into permissive mode. This
+can be done by executing 'setenforce 0' from root shell.
+
+
+Enabling BlueZ debugs
+---------------------
+
+BlueZ debug logs can be enabled in runtime by setting
+"persist.sys.bluetooth.debug" property to either literal "true" or any
+numeric value >0. For example:
+adb root
+adb shell setprop persist.sys.bluetooth.debug 1
+
+After changing property value Bluetooth needs to be restarted to apply changes.
+
+There is also a possibility to enable mgmt debug logs which also enables debugs
+as above. To enable it proceed in the same way as described above but use
+system properties called: persist.sys.bluetooth.mgmtdbg
+
+Note: Debugs are only available on NON USER build variants
+
+
+Customization
+-------------
+
+It is possible to customize BlueZ for Android through Android system properties.
+This may include enabling extra profiles or features inside HALs implementation
+These properties are read on Bluetooth stack startup only and require stack
+restart if changed. All customization properties names start with
+"persist.sys.bluetooth." or "ro.bluetooth." followed by specific HAL name e.g.
+"persist.sys.bluetooth.handsfree". If both are present "persist.sys.bluetooth."
+takes precedence. This allows for read only properties to be set during build
+leaving enough flexibility for developing or debugging purposes.
+This section list available customization options.
+
+Property	Value		Description
+-------------------------------------------
+mode		bredr		Enable BlueZ in BR/EDR mode
+		le		Enable BlueZ in LE mode
+		<none>		Enable BlueZ in default mode - enable BR/EDR/LE
+				if available.
+handsfree	hfp		Enable Handsfree Profile (HFP) with narrowband
+				speech only
+		hfp_wbs		Enable Handsfree Profile (HFP) with narrowband
+				and wideband speech support
+		<none>		Don't enable Handsfree Profile (HFP)
+vendor		<any>		Set vendor name in DIS. If not set fallback to
+				"ro.product.manufacturer".
+model		<any>		Set model name used as default adapter name.
+				If not set fallback to "ro.product.model".
+name		<any>		Set model number in DIS. If not set fallback to
+				"ro.product.name".
+serialno	<any>		Set serial number in DIS. If not set fallback to
+				"ro.serialno".
+systemid	<uint64>	Set system ID in DIS. Hex string encoded uint64.
+pnpid		<any>		PnP information used in DIS and DID profiles.
+				Required format: "Source:VID:PID:Version".
+				Source must be either "bluetooth" or "usb".
+				VID, PID and Version are uint16. Version is
+				optional.
+fwrev		<any>		Firmware revision in DIS. If not set fallback to
+				"ro.build.version.release".
+hwrew		<any>		Hardware revision in DIS. If not set fallback to
+				"ro.board.platform".
+
+
+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 with '-n' parameter and type
+'bluetooth init' in prompt to initialize HAL library. Running without parameter
+will make haltest try to initialize all services after start. On Android
+required bluetoothd service will be started automatically. On Linux it is
+required to start android/bluetoothd manually before init command timeout or
+use provided android/system-emulator, which takes care of launching daemon
+automatically on HAL library initialization. To deinitialize HAL library and
+stop daemon type 'bluetooth cleanup'. Type 'help' for more information. Tab
+completion is also supported.
+
+
+Implementation status
+=====================
+
+Summary of HALs implementation status.
+
+complete    - implementation is feature complete and Android Framework is able
+              to use it normally
+partial     - implementation is in progress and not all required features are
+              present, Android Framework is able to use some of features
+initial     - only initial implementations is present, Android Framework is
+              able to initialize but most likely not able to use it
+not started - no implementation, Android Framework is not able to initialize it
+
+Profile ID        HAL header         4.4 Status    5.0 status
+-------------------------------------------------------------
+core              bluetooth.h        complete      partial
+a2dp              bt_av.h            complete      complete
+gatt              bt_gatt.h          complete      partial
+                  bt_gatt_client.h   complete      partial
+                  bt_gatt_server.h   complete      partial
+handsfree         bt_hf.h            complete      complete
+hidhost           bt_hh.h            complete      complete
+health            bt_hl.h            complete      complete
+pan               bt_pan.h           complete      complete
+avrcp             bt_rc.h            complete      complete
+socket            bt_sock.h          complete      partial
+handsfree_client  bt_hf_client.h     N/A           complete
+map_client        bt_mce.h           N/A           complete
+a2dp_sink         bt_av.h            N/A           partial
+avrcp_ctrl        bt_rc.h            N/A           partial
+
+
+Implementation shortcomings
+===========================
+
+It is possible that some of HAL functionality (although being marked as
+complete) is missing implementation due to reasons like feature feasibility or
+necessity for latest Android Framework. This sections provides list of such
+deficiencies. Note that HAL library is always expected to fully implement HAL
+API so missing implementation might happen only in daemon.
+
+
+HAL Bluetooth
+-------------
+
+methods:
+dut_mode_send                      never called from Android Framework
+le_test_mode                       never called from Android Framework
+
+callbacks:
+dut_mode_recv_cb                   empty JNI implementation
+le_test_mode_cb                    empty JNI implementation
+
+properties:
+BT_PROPERTY_SERVICE_RECORD         not supported for adapter, for device this
+                                   property is returned as a response to
+                                   get_remote_service_record call
+
+BT_PROPERTY_REMOTE_VERSION_INFO    information required by this property (LMP
+                                   information) are not accessible from mgmt
+                                   interface, also marking this property as
+                                   settable is probably a typo in HAL header
+
+HAL Socket
+----------
+
+Support only for BTSOCK_RFCOMM socket type.
+
+
+HAL AVRCP
+---------
+
+methods:
+list_player_app_attr_rsp           never called from Android Framework
+list_player_app_value_rsp          never called from Android Framework
+get_player_app_value_rsp           never called from Android Framework
+get_player_app_attr_text_rsp       never called from Android Framework
+get_player_app_value_text_rsp      never called from Android Framework
+set_player_app_value_rsp           never called from Android Framework
+
+callbacks:
+list_player_app_attr_cb            NULL JNI implementation
+list_player_app_values_cb          NULL JNI implementation
+get_player_app_value_cb            NULL JNI implementation
+get_player_app_attrs_text_cb       NULL JNI implementation
+get_player_app_values_text_cb      NULL JNI implementation
+set_player_app_value_cb            NULL JNI implementation
+
+
+HAL GATT
+--------
+
+methods:
+client->set_adv_data               missing kernel support for vendor data
+client->connect                    is_direct parameter is ignored
+
+
+Audio SCO HAL
+=============
+
+When Bluetooth chip's audio is not wired directly to device audio, Audio SCO
+HAL is used to enable SCO support. It needs to be loaded by AudioFlinger
+following audio_policy.conf configuration. Example of configuration is shown
+below:
+
+...
+  sco {
+    outputs {
+      sco {
+        sampling_rates 8000|44100
+        channel_masks AUDIO_CHANNEL_OUT_STEREO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_OUT_ALL_SCO
+      }
+    }
+    inputs {
+      sco {
+        sampling_rates 8000|44100
+        channel_masks AUDIO_CHANNEL_IN_MONO
+        formats AUDIO_FORMAT_PCM_16_BIT
+        devices AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET
+      }
+    }
+  }
+...
+
+Known Android issues
+====================
+
+It is possible that BlueZ is triggering bugs on Android Framework that could
+affect qualification or user experience. This section provides list of
+recommended Android fixes that are not part of latest AOSP release supported by
+BlueZ.
+
+For Android 5.1 Lollipop:
+https://android-review.googlesource.com/177314
+
+For Android 5.0 Lollipop:
+https://android-review.googlesource.com/99761
+https://android-review.googlesource.com/100297
+https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/132733
+https://android-review.googlesource.com/132763
+https://android-review.googlesource.com/177314
+
+For Android 4.4 KitKat:
+https://android-review.googlesource.com/82757
+https://android-review.googlesource.com/87670
+https://android-review.googlesource.com/88384
+https://android-review.googlesource.com/99761
+https://android-review.googlesource.com/99850
+https://android-review.googlesource.com/100297
+https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/177314
+
+Unimplemented Bluetooth features
+================================
+
+Some Bluetooth functionality require support from outside of BT stack
+eg. telephony stack. This sections describes profiles optional features not
+implemented due to lack of support in other Android subsystems or missing API
+in respective BT HALs.
+
+Profile		Feature				Comments
+--------------------------------------------------------
+HFP		Attach a phone number to	AT+BINP=1
+		a voice tag
+HFP		Enhanced Call Control		AT+CHLD={1x,2x}
+HFP		Explicit Call Transfer		AT+CHLD=4
+HFP		Response and Hold		AT+BTRH, +BTRH
+HFP		In-band Ring Tone		+BSIR
+AVRCP		Player Settings			HAL API present but not used
+AVRCP		Browsing			No HAL API
+GATT		Read multiple characteristics	No HAL API
+
+
+Reporting Bugs
+==============
+
+Bugs should be reported at https://01.org/jira/browse/BA. When reporting
+a bug please attach logs from logcat (logcat -v time) and HCI trace. Daemon
+debug logs should be enabled. When reporting daemon crash please run it under
+valgrind if possible. For details on how to enabled debug logs and valgrind see
+"Enabling BlueZ debugs" section.
diff --git a/repo/android/a2dp-sink.c b/repo/android/a2dp-sink.c
new file mode 100644
index 0000000..7c1e1a0
--- /dev/null
+++ b/repo/android/a2dp-sink.c
@@ -0,0 +1,84 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "a2dp-sink.h"
+
+static struct ipc *hal_ipc = NULL;
+
+static void bt_a2dp_sink_connect(const void *buf, uint16_t len)
+{
+	/* TODO */
+
+	DBG("");
+
+	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_CONNECT,
+							HAL_STATUS_UNSUPPORTED);
+}
+
+static void bt_a2dp_sink_disconnect(const void *buf, uint16_t len)
+{
+	/* TODO */
+
+	DBG("");
+
+	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_DISCONNECT,
+							HAL_STATUS_UNSUPPORTED);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+	/* HAL_OP_A2DP_CONNECT */
+	{ bt_a2dp_sink_connect, false, sizeof(struct hal_cmd_a2dp_connect) },
+	/* HAL_OP_A2DP_DISCONNECT */
+	{ bt_a2dp_sink_disconnect, false,
+				sizeof(struct hal_cmd_a2dp_disconnect) },
+};
+
+bool bt_a2dp_sink_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
+{
+	DBG("");
+
+	hal_ipc = ipc;
+	ipc_register(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, cmd_handlers,
+						G_N_ELEMENTS(cmd_handlers));
+
+	return true;
+}
+
+void bt_a2dp_sink_unregister(void)
+{
+	DBG("");
+
+	ipc_unregister(hal_ipc, HAL_SERVICE_ID_A2DP_SINK);
+	hal_ipc = NULL;
+}
diff --git a/repo/android/a2dp-sink.h b/repo/android/a2dp-sink.h
new file mode 100644
index 0000000..d2c5ff4
--- /dev/null
+++ b/repo/android/a2dp-sink.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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
+ *
+ */
+
+bool bt_a2dp_sink_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
+void bt_a2dp_sink_unregister(void);
diff --git a/repo/android/a2dp.c b/repo/android/a2dp.c
new file mode 100644
index 0000000..f219042
--- /dev/null
+++ b/repo/android/a2dp.c
@@ -0,0 +1,1774 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013-2014  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
+ *
+ */
+
+#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 "profiles/audio/a2dp-codecs.h"
+#include "src/shared/queue.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc-common.h"
+#include "ipc.h"
+#include "a2dp.h"
+#include "utils.h"
+#include "bluetooth.h"
+#include "avdtp.h"
+#include "avrcp.h"
+#include "audio-msg.h"
+
+#define SVC_HINT_CAPTURING 0x08
+#define IDLE_TIMEOUT 1
+#define AUDIO_RETRY_TIMEOUT 2
+
+static GIOChannel *server = NULL;
+static GSList *devices = NULL;
+static GSList *endpoints = NULL;
+static GSList *setups = NULL;
+static bdaddr_t adapter_addr;
+static uint32_t record_id = 0;
+static guint audio_retry_id = 0;
+static bool audio_retrying = false;
+
+static struct ipc *hal_ipc = NULL;
+static struct ipc *audio_ipc = NULL;
+
+static struct queue *lseps = NULL;
+
+struct a2dp_preset {
+	void *data;
+	int8_t len;
+};
+
+struct a2dp_endpoint {
+	uint8_t id;
+	uint8_t codec;
+	struct avdtp_local_sep *sep;
+	struct a2dp_preset *caps;
+	GSList *presets;
+};
+
+struct a2dp_device {
+	bdaddr_t	dst;
+	uint8_t		state;
+	GIOChannel	*io;
+	struct avdtp	*session;
+	guint		idle_id;
+};
+
+struct a2dp_setup {
+	struct a2dp_device *dev;
+	struct a2dp_endpoint *endpoint;
+	struct a2dp_preset *preset;
+	struct avdtp_stream *stream;
+	uint8_t state;
+};
+
+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 preset_free(void *data)
+{
+	struct a2dp_preset *preset = data;
+
+	g_free(preset->data);
+	g_free(preset);
+}
+
+static void unregister_endpoint(void *data)
+{
+	struct a2dp_endpoint *endpoint = data;
+
+	if (endpoint->sep)
+		avdtp_unregister_sep(lseps, endpoint->sep);
+
+	if (endpoint->caps)
+		preset_free(endpoint->caps);
+
+	g_slist_free_full(endpoint->presets, preset_free);
+
+	g_free(endpoint);
+}
+
+static void setup_free(void *data)
+{
+	struct a2dp_setup *setup = data;
+
+	if (!g_slist_find(setup->endpoint->presets, setup->preset))
+		preset_free(setup->preset);
+
+	g_free(setup);
+}
+
+static void setup_remove(struct a2dp_setup *setup)
+{
+	setups = g_slist_remove(setups, setup);
+	setup_free(setup);
+}
+
+static void setup_remove_all_by_dev(struct a2dp_device *dev)
+{
+	GSList *l = setups;
+
+	while (l) {
+		struct a2dp_setup *setup = l->data;
+		GSList *next = g_slist_next(l);
+
+		if (setup->dev == dev)
+			setup_remove(setup);
+
+		l = next;
+	}
+}
+
+static void a2dp_device_free(void *data)
+{
+	struct a2dp_device *dev = data;
+
+	if (dev->idle_id > 0)
+		g_source_remove(dev->idle_id);
+
+	if (dev->session)
+		avdtp_unref(dev->session);
+
+	if (dev->io) {
+		g_io_channel_shutdown(dev->io, FALSE, NULL);
+		g_io_channel_unref(dev->io);
+	}
+
+	setup_remove_all_by_dev(dev);
+
+	g_free(dev);
+}
+
+static void a2dp_device_remove(struct a2dp_device *dev)
+{
+	devices = g_slist_remove(devices, dev);
+	a2dp_device_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 bool a2dp_device_connect(struct a2dp_device *dev, BtIOConnect cb)
+{
+	GError *err = NULL;
+
+	dev->io = bt_io_connect(cb, dev, NULL, &err,
+					BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+					BT_IO_OPT_DEST_BDADDR, &dev->dst,
+					BT_IO_OPT_PSM, AVDTP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+					BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		return false;
+	}
+
+	return true;
+}
+
+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_notif(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_EV_A2DP_CONN_STATE,
+							sizeof(ev), &ev);
+
+	if (state != HAL_A2DP_STATE_DISCONNECTED)
+		return;
+
+	bt_avrcp_disconnect(&dev->dst);
+
+	a2dp_device_remove(dev);
+}
+
+static void bt_audio_notify_state(struct a2dp_setup *setup, uint8_t state)
+{
+	struct hal_ev_a2dp_audio_state ev;
+	char address[18];
+
+	if (setup->state == state)
+		return;
+
+	setup->state = state;
+
+	ba2str(&setup->dev->dst, address);
+	DBG("device %s state %u", address, state);
+
+	bdaddr2android(&setup->dev->dst, ev.bdaddr);
+	ev.state = state;
+
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_EV_A2DP_AUDIO_STATE,
+							sizeof(ev), &ev);
+}
+
+static void disconnect_cb(void *user_data)
+{
+	struct a2dp_device *dev = user_data;
+
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+}
+
+static int sbc_check_config(void *caps, uint8_t caps_len, void *conf,
+							uint8_t conf_len)
+{
+	a2dp_sbc_t *cap, *config;
+
+	if (conf_len != caps_len || conf_len != sizeof(a2dp_sbc_t)) {
+		error("SBC: Invalid configuration size (%u)", conf_len);
+		return -EINVAL;
+	}
+
+	cap = caps;
+	config = conf;
+
+	if (!(cap->frequency & config->frequency)) {
+		error("SBC: Unsupported frequency (%u) by endpoint",
+							config->frequency);
+		return -EINVAL;
+	}
+
+	if (!(cap->channel_mode & config->channel_mode)) {
+		error("SBC: Unsupported channel mode (%u) by endpoint",
+							config->channel_mode);
+		return -EINVAL;
+	}
+
+	if (!(cap->block_length & config->block_length)) {
+		error("SBC: Unsupported block length (%u) by endpoint",
+							config->block_length);
+		return -EINVAL;
+	}
+
+	if (!(cap->allocation_method & config->allocation_method)) {
+		error("SBC: Unsupported allocation method (%u) by endpoint",
+							config->block_length);
+		return -EINVAL;
+	}
+
+	if (config->max_bitpool < cap->min_bitpool) {
+		error("SBC: Invalid maximun bitpool (%u < %u)",
+					config->max_bitpool, cap->min_bitpool);
+		return -EINVAL;
+	}
+
+	if (config->min_bitpool > cap->max_bitpool) {
+		error("SBC: Invalid minimun bitpool (%u > %u)",
+					config->min_bitpool, cap->min_bitpool);
+		return -EINVAL;
+	}
+
+	if (config->max_bitpool > cap->max_bitpool)
+		return -ERANGE;
+
+	if (config->min_bitpool < cap->min_bitpool)
+		return -ERANGE;
+
+	return 0;
+}
+
+static int aac_check_config(void *caps, uint8_t caps_len, void *conf,
+							uint8_t conf_len)
+{
+	a2dp_aac_t *cap, *config;
+
+	if (conf_len != caps_len || conf_len != sizeof(a2dp_aac_t)) {
+		error("AAC: Invalid configuration size (%u)", conf_len);
+		return -EINVAL;
+	}
+
+	cap = caps;
+	config = conf;
+
+	if (!(cap->object_type & config->object_type)) {
+		error("AAC: Unsupported object type (%u) by endpoint",
+							config->object_type);
+		return -EINVAL;
+	}
+
+	if (!(AAC_GET_FREQUENCY(*cap) & AAC_GET_FREQUENCY(*config))) {
+		error("AAC: Unsupported frequency (%u) by endpoint",
+						AAC_GET_FREQUENCY(*config));
+		return -EINVAL;
+	}
+
+	if (!(cap->channels & config->channels)) {
+		error("AAC: Unsupported channels (%u) by endpoint",
+							config->channels);
+		return -EINVAL;
+	}
+
+	/* VBR support in SNK is mandatory but let's make sure we don't try to
+	 * have VBR on remote which for some reason does not support it
+	 */
+	if (!cap->vbr && config->vbr) {
+		error("AAC: Unsupported VBR (%u) by endpoint",
+							config->vbr);
+		return -EINVAL;
+	}
+
+	if (AAC_GET_BITRATE(*cap) < AAC_GET_BITRATE(*config))
+		return -ERANGE;
+
+	return 0;
+}
+
+static int aptx_check_config(void *caps, uint8_t caps_len, void *conf,
+							uint8_t conf_len)
+{
+	a2dp_aptx_t *cap, *config;
+
+	if (conf_len != caps_len || conf_len != sizeof(a2dp_aptx_t)) {
+		error("APTX: Invalid configuration size (%u)", conf_len);
+		return -EINVAL;
+	}
+
+	cap = caps;
+	config = conf;
+
+	if (!(cap->frequency & config->frequency)) {
+		error("APTX: Unsupported frequenct (%u) by endpoint",
+							config->frequency);
+		return -EINVAL;
+	}
+
+	if (!(cap->channel_mode & config->channel_mode)) {
+		error("APTX: Unsupported channel mode (%u) by endpoint",
+							config->channel_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int check_capabilities(struct a2dp_preset *preset,
+				struct avdtp_media_codec_capability *codec,
+				uint8_t codec_len)
+{
+	a2dp_vendor_codec_t *vndcodec;
+
+	/* Codec specific */
+	switch (codec->media_codec_type) {
+	case A2DP_CODEC_SBC:
+		return sbc_check_config(codec->data, codec_len, preset->data,
+								preset->len);
+	case A2DP_CODEC_MPEG24:
+		return aac_check_config(codec->data, codec_len, preset->data,
+								preset->len);
+	case A2DP_CODEC_VENDOR:
+		vndcodec = (void *) codec->data;
+		if (btohl(vndcodec->vendor_id) == APTX_VENDOR_ID &&
+				btohs(vndcodec->codec_id) == APTX_CODEC_ID)
+			return aptx_check_config(codec->data, codec_len,
+						preset->data, preset->len);
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct a2dp_preset *sbc_select_range(void *caps, uint8_t caps_len,
+						void *conf, uint8_t conf_len)
+{
+	struct a2dp_preset *p;
+	a2dp_sbc_t *cap, *config;
+
+	cap = caps;
+	config = conf;
+
+	config->min_bitpool = MAX(config->min_bitpool, cap->min_bitpool);
+	config->max_bitpool = MIN(config->max_bitpool, cap->max_bitpool);
+
+	p = g_new0(struct a2dp_preset, 1);
+	p->len = conf_len;
+	p->data = g_memdup(conf, p->len);
+
+	return p;
+}
+
+static struct a2dp_preset *aac_select_range(void *caps, uint8_t caps_len,
+						void *conf, uint8_t conf_len)
+{
+	struct a2dp_preset *p;
+	a2dp_aac_t *cap, *config;
+	uint32_t bitrate;
+
+	cap = caps;
+	config = conf;
+
+	bitrate = MIN(AAC_GET_BITRATE(*cap), AAC_GET_BITRATE(*config));
+	AAC_SET_BITRATE(*config, bitrate);
+
+	p = g_new0(struct a2dp_preset, 1);
+	p->len = conf_len;
+	p->data = g_memdup(conf, p->len);
+
+	return p;
+}
+
+static struct a2dp_preset *select_preset_range(struct a2dp_preset *preset,
+				struct avdtp_media_codec_capability *codec,
+				uint8_t codec_len)
+{
+	/* Codec specific */
+	switch (codec->media_codec_type) {
+	case A2DP_CODEC_SBC:
+		return sbc_select_range(codec->data, codec_len, preset->data,
+								preset->len);
+	case A2DP_CODEC_MPEG24:
+		return aac_select_range(codec->data, codec_len, preset->data,
+								preset->len);
+	default:
+		return NULL;
+	}
+}
+
+static struct a2dp_preset *select_preset(struct a2dp_endpoint *endpoint,
+						struct avdtp_remote_sep *rsep)
+{
+	struct avdtp_service_capability *service;
+	struct avdtp_media_codec_capability *codec;
+	GSList *l;
+	uint8_t codec_len;
+
+	service = avdtp_get_codec(rsep);
+	codec = (struct avdtp_media_codec_capability *) service->data;
+	codec_len = service->length - sizeof(*codec);
+
+	for (l = endpoint->presets; l; l = g_slist_next(l)) {
+		struct a2dp_preset *preset = l->data;
+		int err;
+
+		err = check_capabilities(preset, codec, codec_len);
+		if (err == 0)
+			return preset;
+
+		if (err == -ERANGE)
+			return select_preset_range(preset, codec, codec_len);
+	}
+
+	return NULL;
+}
+
+static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
+			struct a2dp_preset *preset, struct avdtp_stream *stream)
+{
+	struct a2dp_setup *setup;
+
+	setup = g_new0(struct a2dp_setup, 1);
+	setup->dev = dev;
+	setup->endpoint = endpoint;
+	setup->preset = preset;
+	setup->stream = stream;
+	setups = g_slist_append(setups, setup);
+
+	if (dev->idle_id > 0) {
+		g_source_remove(dev->idle_id);
+		dev->idle_id = 0;
+	}
+}
+
+static int select_configuration(struct a2dp_device *dev,
+				struct a2dp_endpoint *endpoint,
+				struct avdtp_remote_sep *rsep)
+{
+	struct a2dp_preset *preset;
+	struct avdtp_stream *stream;
+	struct avdtp_service_capability *service;
+	struct avdtp_media_codec_capability *codec;
+	GSList *caps;
+	int err;
+
+	preset = select_preset(endpoint, rsep);
+	if (!preset) {
+		error("Unable to select codec preset");
+		return -EINVAL;
+	}
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+	caps = g_slist_append(NULL, service);
+
+	codec = g_malloc0(sizeof(*codec) + preset->len);
+	codec->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+	codec->media_codec_type = endpoint->codec;
+	memcpy(codec->data, preset->data, preset->len);
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec,
+						sizeof(*codec) + preset->len);
+	caps = g_slist_append(caps, service);
+
+	g_free(codec);
+
+	err = avdtp_set_configuration(dev->session, rsep, endpoint->sep, caps,
+								&stream);
+	g_slist_free_full(caps, g_free);
+	if (err < 0) {
+		error("avdtp_set_configuration: %s", strerror(-err));
+		return err;
+	}
+
+	setup_add(dev, endpoint, preset, stream);
+
+	return 0;
+}
+
+static void discover_cb(struct avdtp *session, GSList *seps,
+				struct avdtp_error *err, void *user_data)
+{
+	struct a2dp_device *dev = user_data;
+	struct a2dp_endpoint *endpoint = NULL;
+	struct avdtp_remote_sep *rsep = NULL;
+	GSList *l;
+
+	for (l = endpoints; l; l = g_slist_next(l)) {
+		endpoint = l->data;
+
+		rsep = avdtp_find_remote_sep(session, endpoint->sep);
+		if (rsep)
+			break;
+	}
+
+	if (!rsep) {
+		error("Unable to find matching endpoint");
+		goto failed;
+	}
+
+	if (select_configuration(dev, endpoint, rsep) < 0)
+		goto failed;
+
+	return;
+
+failed:
+	avdtp_shutdown(session);
+}
+
+static gboolean idle_timeout(gpointer user_data)
+{
+	struct a2dp_device *dev = user_data;
+	int err;
+
+	dev->idle_id = 0;
+
+	err = avdtp_discover(dev->session, discover_cb, dev);
+	if (err == 0)
+		return FALSE;
+
+	error("avdtp_discover: %s", strerror(-err));
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+
+	return FALSE;
+}
+
+static void signaling_connect_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct a2dp_device *dev = user_data;
+	struct avdtp *session;
+	uint16_t imtu, omtu;
+	GError *gerr = NULL;
+	int fd;
+
+	if (err) {
+		bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+		error("%s", err->message);
+		return;
+	}
+
+	bt_io_get(chan, &gerr,
+			BT_IO_OPT_IMTU, &imtu,
+			BT_IO_OPT_OMTU, &omtu,
+			BT_IO_OPT_INVALID);
+	if (gerr) {
+		error("%s", gerr->message);
+		g_error_free(gerr);
+		goto failed;
+	}
+
+	fd = g_io_channel_unix_get_fd(chan);
+
+	/* FIXME: Add proper version */
+	session = avdtp_new(fd, imtu, omtu, 0x0100, lseps);
+	if (!session)
+		goto failed;
+
+	dev->session = session;
+
+	avdtp_add_disconnect_cb(dev->session, disconnect_cb, dev);
+
+	/* Proceed to stream setup if initiator */
+	if (dev->io) {
+		int perr;
+
+		g_io_channel_unref(dev->io);
+		dev->io = NULL;
+
+		perr = avdtp_discover(dev->session, discover_cb, dev);
+		if (perr < 0) {
+			error("avdtp_discover: %s", strerror(-perr));
+			goto failed;
+		}
+		bt_avrcp_connect(&dev->dst);
+	} else /* Init idle timeout to discover */
+		dev->idle_id = g_timeout_add_seconds(IDLE_TIMEOUT, idle_timeout,
+									dev);
+
+	return;
+
+failed:
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+}
+
+static void bt_a2dp_connect(const void *buf, uint16_t len)
+{
+	const struct hal_cmd_a2dp_connect *cmd = buf;
+	struct a2dp_device *dev;
+	uint8_t status;
+	char addr[18];
+	bdaddr_t dst;
+	GSList *l;
+
+	DBG("");
+
+	android2bdaddr(&cmd->bdaddr, &dst);
+
+	l = g_slist_find_custom(devices, &dst, device_cmp);
+	if (l) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	dev = a2dp_device_new(&dst);
+	if (!a2dp_device_connect(dev, signaling_connect_cb)) {
+		a2dp_device_remove(dev);
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	ba2str(&dev->dst, addr);
+	DBG("connecting to %s", addr);
+
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
+
+	status = HAL_STATUS_SUCCESS;
+
+failed:
+	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_CONNECT, status);
+}
+
+static void bt_a2dp_disconnect(const void *buf, uint16_t len)
+{
+	const struct hal_cmd_a2dp_connect *cmd = buf;
+	uint8_t status;
+	struct a2dp_device *dev;
+	GSList *l;
+	bdaddr_t dst;
+
+	DBG("");
+
+	android2bdaddr(&cmd->bdaddr, &dst);
+
+	l = g_slist_find_custom(devices, &dst, device_cmp);
+	if (!l) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	dev = l->data;
+	status = HAL_STATUS_SUCCESS;
+
+	if (dev->io) {
+		bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+		goto failed;
+	}
+
+	/* Wait AVDTP session to shutdown */
+	avdtp_shutdown(dev->session);
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTING);
+
+failed:
+	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_DISCONNECT,
+									status);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+	/* HAL_OP_A2DP_CONNECT */
+	{ bt_a2dp_connect, false, sizeof(struct hal_cmd_a2dp_connect) },
+	/* HAL_OP_A2DP_DISCONNECT */
+	{ bt_a2dp_disconnect, false, sizeof(struct hal_cmd_a2dp_disconnect) },
+};
+
+static struct a2dp_setup *find_setup_by_device(struct a2dp_device *dev)
+{
+	GSList *l;
+
+	for (l = setups; l; l = g_slist_next(l)) {
+		struct a2dp_setup *setup = l->data;
+
+		if (setup->dev == dev)
+			return setup;
+	}
+
+	return NULL;
+}
+
+static void transport_connect_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct a2dp_device *dev = user_data;
+	struct a2dp_setup *setup;
+	uint16_t imtu, omtu;
+	GError *gerr = NULL;
+	int fd;
+
+	if (err) {
+		error("%s", err->message);
+		return;
+	}
+
+	setup = find_setup_by_device(dev);
+	if (!setup) {
+		error("Unable to find stream setup");
+		return;
+	}
+
+	bt_io_get(chan, &gerr,
+			BT_IO_OPT_IMTU, &imtu,
+			BT_IO_OPT_OMTU, &omtu,
+			BT_IO_OPT_INVALID);
+	if (gerr) {
+		error("%s", gerr->message);
+		g_error_free(gerr);
+		return;
+	}
+
+	fd = g_io_channel_unix_get_fd(chan);
+
+	if (!avdtp_stream_set_transport(setup->stream, fd, imtu, omtu)) {
+		error("avdtp_stream_set_transport: failed");
+		return;
+	}
+
+	g_io_channel_set_close_on_unref(chan, FALSE);
+
+	if (dev->io) {
+		g_io_channel_unref(dev->io);
+		dev->io = NULL;
+	}
+
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTED);
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	struct a2dp_device *dev;
+	bdaddr_t dst;
+	char address[18];
+	GError *gerr = NULL;
+	GSList *l;
+
+	if (err) {
+		error("%s", err->message);
+		return;
+	}
+
+	bt_io_get(chan, &gerr,
+			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;
+	}
+
+	ba2str(&dst, address);
+	DBG("Incoming connection from %s", address);
+
+	l = g_slist_find_custom(devices, &dst, device_cmp);
+	if (l) {
+		transport_connect_cb(chan, err, l->data);
+		return;
+	}
+
+	dev = a2dp_device_new(&dst);
+	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
+	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(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID);
+	svclass_id = sdp_list_append(NULL, &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(NULL, &profile[0]);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
+	psm = sdp_data_alloc(SDP_UINT16, &lp);
+	proto[0] = sdp_list_append(proto[0], psm);
+	apseq = sdp_list_append(NULL, proto[0]);
+
+	sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
+	proto[1] = sdp_list_append(NULL, &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(NULL, 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", NULL, NULL);
+
+	sdp_data_free(psm);
+	sdp_data_free(version);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(pfseq, NULL);
+	sdp_list_free(aproto, NULL);
+	sdp_list_free(root, NULL);
+	sdp_list_free(svclass_id, NULL);
+
+	return record;
+}
+
+static gboolean sep_getcap_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					GSList **caps, uint8_t *err,
+					void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_preset *cap = endpoint->caps;
+	struct avdtp_service_capability *service;
+	struct avdtp_media_codec_capability *codec;
+
+	*caps = NULL;
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+	*caps = g_slist_append(*caps, service);
+
+	codec = g_malloc0(sizeof(*codec) + cap->len);
+	codec->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+	codec->media_codec_type = endpoint->codec;
+	memcpy(codec->data, cap->data, cap->len);
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec,
+						sizeof(*codec) + cap->len);
+	*caps = g_slist_append(*caps, service);
+	g_free(codec);
+
+	return TRUE;
+}
+
+static int check_config(struct a2dp_endpoint *endpoint,
+						struct a2dp_preset *config)
+{
+	GSList *l;
+	struct a2dp_preset *caps;
+
+	for (l = endpoint->presets; l; l = g_slist_next(l)) {
+		struct a2dp_preset *preset = l->data;
+
+		if (preset->len != config->len)
+			continue;
+
+		if (memcmp(preset->data, config->data, preset->len) == 0)
+			return 0;
+	}
+
+	caps = endpoint->caps;
+
+	/* Codec specific */
+	switch (endpoint->codec) {
+	case A2DP_CODEC_SBC:
+		return sbc_check_config(caps->data, caps->len, config->data,
+								config->len);
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct a2dp_device *find_device_by_session(struct avdtp *session)
+{
+	GSList *l;
+
+	for (l = devices; l; l = g_slist_next(l)) {
+		struct a2dp_device *dev = l->data;
+
+		if (dev->session == session)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static struct a2dp_setup *find_setup(uint8_t id)
+{
+	GSList *l;
+
+	for (l = setups; l; l = g_slist_next(l)) {
+		struct a2dp_setup *setup = l->data;
+
+		if (setup->endpoint->id == id)
+			return setup;
+	}
+
+	return NULL;
+}
+
+static void setup_remove_by_id(uint8_t id)
+{
+	struct a2dp_setup *setup;
+
+	setup = find_setup(id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u", id);
+		return;
+	}
+
+	setup_remove(setup);
+}
+
+static gboolean sep_setconf_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						GSList *caps,
+						avdtp_set_configuration_cb cb,
+						void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_device *dev;
+	struct a2dp_preset *preset = NULL;
+
+	DBG("");
+
+	dev = find_device_by_session(session);
+	if (!dev) {
+		error("Unable to find device for session %p", session);
+		return FALSE;
+	}
+
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec;
+
+		if (cap->category == AVDTP_DELAY_REPORTING)
+			return FALSE;
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		codec = (struct avdtp_media_codec_capability *) cap->data;
+
+		if (codec->media_codec_type != endpoint->codec)
+			return FALSE;
+
+		preset = g_new0(struct a2dp_preset, 1);
+		preset->len = cap->length - sizeof(*codec);
+		preset->data = g_memdup(codec->data, preset->len);
+
+		if (check_config(endpoint, preset) < 0) {
+			preset_free(preset);
+			return FALSE;
+		}
+	}
+
+	if (!preset)
+		return FALSE;
+
+	setup_add(dev, endpoint, preset, stream);
+
+	cb(session, stream, NULL);
+
+	return TRUE;
+}
+
+static gboolean sep_open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u",
+								endpoint->id);
+		*err = AVDTP_SEP_NOT_IN_USE;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean sep_close_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						uint8_t *err,
+						void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u",
+								endpoint->id);
+		*err = AVDTP_SEP_NOT_IN_USE;
+		return FALSE;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+	setup_remove(setup);
+
+	return TRUE;
+}
+
+static gboolean sep_start_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						uint8_t *err,
+						void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u",
+								endpoint->id);
+		*err = AVDTP_SEP_NOT_IN_USE;
+		return FALSE;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_STARTED);
+
+	return TRUE;
+}
+
+static gboolean sep_suspend_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						uint8_t *err,
+						void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u",
+								endpoint->id);
+		*err = AVDTP_SEP_NOT_IN_USE;
+		return FALSE;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_SUSPEND);
+
+	return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+	.get_capability		= sep_getcap_ind,
+	.set_configuration	= sep_setconf_ind,
+	.open			= sep_open_ind,
+	.close			= sep_close_ind,
+	.start			= sep_start_ind,
+	.suspend		= sep_suspend_ind,
+};
+
+static void sep_setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+	int ret;
+
+	DBG("");
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for endpoint %u",
+								endpoint->id);
+		return;
+	}
+
+	if (err)
+		goto failed;
+
+	ret = avdtp_open(session, stream);
+	if (ret < 0) {
+		error("avdtp_open: %s", strerror(-ret));
+		goto failed;
+	}
+
+	return;
+
+failed:
+	setup_remove(setup);
+}
+
+static void sep_open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_device *dev;
+
+	DBG("");
+
+	if (err)
+		goto failed;
+
+	dev = find_device_by_session(session);
+	if (!dev) {
+		error("Unable to find device for session");
+		goto failed;
+	}
+
+	a2dp_device_connect(dev, transport_connect_cb);
+
+	return;
+
+failed:
+	setup_remove_by_id(endpoint->id);
+}
+
+static void sep_start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	if (err) {
+		setup_remove_by_id(endpoint->id);
+		return;
+	}
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for %u endpoint",
+								endpoint->id);
+		return;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_STARTED);
+}
+
+static void sep_suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	if (err) {
+		setup_remove_by_id(endpoint->id);
+		return;
+	}
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for %u endpoint",
+								endpoint->id);
+		return;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+}
+
+static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_setup *setup;
+
+	DBG("");
+
+	if (err)
+		return;
+
+	setup = find_setup(endpoint->id);
+	if (!setup) {
+		error("Unable to find stream setup for %u endpoint",
+								endpoint->id);
+		return;
+	}
+
+	bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+	setup_remove(setup);
+}
+
+static void sep_abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+
+	DBG("");
+
+	if (err)
+		return;
+
+	setup_remove_by_id(endpoint->id);
+}
+
+static struct avdtp_sep_cfm sep_cfm = {
+	.set_configuration	= sep_setconf_cfm,
+	.open			= sep_open_cfm,
+	.start			= sep_start_cfm,
+	.suspend		= sep_suspend_cfm,
+	.close			= sep_close_cfm,
+	.abort			= sep_abort_cfm,
+};
+
+static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
+							GSList *presets)
+{
+	struct a2dp_endpoint *endpoint;
+
+	/* FIXME: Add proper check for uuid */
+
+	endpoint = g_new0(struct a2dp_endpoint, 1);
+	endpoint->id = g_slist_length(endpoints) + 1;
+	endpoint->codec = codec;
+	endpoint->sep = avdtp_register_sep(lseps, AVDTP_SEP_TYPE_SOURCE,
+						AVDTP_MEDIA_TYPE_AUDIO,
+						codec, FALSE, &sep_ind,
+						&sep_cfm, endpoint);
+	endpoint->caps = presets->data;
+	endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
+
+	if (endpoint->codec == A2DP_CODEC_VENDOR) {
+		a2dp_vendor_codec_t *vndcodec = (void *) endpoint->caps->data;
+
+		avdtp_sep_set_vendor_codec(endpoint->sep,
+						btohl(vndcodec->vendor_id),
+						btohs(vndcodec->codec_id));
+	}
+
+	endpoints = g_slist_append(endpoints, endpoint);
+
+	return endpoint->id;
+}
+
+static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
+								uint16_t len)
+{
+	GSList *l = NULL;
+	uint8_t i;
+
+	for (i = 0; count > i; i++) {
+		const uint8_t *ptr = (const uint8_t *) p;
+		struct a2dp_preset *preset;
+
+		if (len < sizeof(struct audio_preset)) {
+			DBG("Invalid preset index %u", i);
+			g_slist_free_full(l, preset_free);
+			return NULL;
+		}
+
+		len -= sizeof(struct audio_preset);
+		if (len == 0 || len < p->len) {
+			DBG("Invalid preset size of %u for index %u", len, i);
+			g_slist_free_full(l, preset_free);
+			return NULL;
+		}
+
+		preset = g_new0(struct a2dp_preset, 1);
+		preset->len = p->len;
+		preset->data = g_memdup(p->data, preset->len);
+		l = g_slist_append(l, preset);
+
+		len -= preset->len;
+		ptr += sizeof(*p) + preset->len;
+		p = (const struct audio_preset *) ptr;
+	}
+
+	return l;
+}
+
+static void bt_audio_open(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_open *cmd = buf;
+	struct audio_rsp_open rsp;
+	GSList *presets;
+
+	DBG("");
+
+	audio_retrying = false;
+
+	if (cmd->presets == 0) {
+		error("No audio presets found");
+		goto failed;
+	}
+
+	presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
+	if (!presets) {
+		error("No audio presets found");
+		goto failed;
+	}
+
+	rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
+	if (rsp.id == 0) {
+		g_slist_free_full(presets, preset_free);
+		error("Unable to register endpoint");
+		goto failed;
+	}
+
+	g_slist_free(presets);
+
+	ipc_send_rsp_full(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN,
+							sizeof(rsp), &rsp, -1);
+
+	return;
+
+failed:
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN,
+							AUDIO_STATUS_FAILED);
+}
+
+static struct a2dp_endpoint *find_endpoint(uint8_t id)
+{
+	GSList *l;
+
+	for (l = endpoints; l; l = g_slist_next(l)) {
+		struct a2dp_endpoint *endpoint = l->data;
+
+		if (endpoint->id == id)
+			return endpoint;
+	}
+
+	return NULL;
+}
+
+static void bt_audio_close(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_close *cmd = buf;
+	struct a2dp_endpoint *endpoint;
+
+	DBG("");
+
+	endpoint = find_endpoint(cmd->id);
+	if (!endpoint) {
+		error("Unable to find endpoint %u", cmd->id);
+		ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE,
+							AUDIO_STATUS_FAILED);
+		return;
+	}
+
+	endpoints = g_slist_remove(endpoints, endpoint);
+	unregister_endpoint(endpoint);
+
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE,
+							AUDIO_STATUS_SUCCESS);
+}
+
+static void bt_stream_open(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_open_stream *cmd = buf;
+	struct audio_rsp_open_stream *rsp;
+	struct a2dp_setup *setup;
+	int fd;
+	uint16_t omtu;
+
+	DBG("");
+
+	if (cmd->id)
+		setup = find_setup(cmd->id);
+	else
+		setup = setups ? setups->data : NULL;
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+							AUDIO_STATUS_FAILED);
+		return;
+	}
+
+	if (!avdtp_stream_get_transport(setup->stream, &fd, NULL, &omtu,
+								NULL)) {
+		error("avdtp_stream_get_transport: failed");
+		ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+							AUDIO_STATUS_FAILED);
+		return;
+	}
+
+	len = sizeof(struct audio_rsp_open_stream) +
+			sizeof(struct audio_preset) + setup->preset->len;
+	rsp = g_malloc0(len);
+	rsp->id = setup->endpoint->id;
+	rsp->mtu = omtu;
+	rsp->preset->len = setup->preset->len;
+	memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
+
+	ipc_send_rsp_full(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+								len, rsp, fd);
+
+	g_free(rsp);
+}
+
+static void bt_stream_close(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_close_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
+
+	DBG("");
+
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	err = avdtp_close(setup->dev->session, setup->stream, FALSE);
+	if (err < 0) {
+		error("avdtp_close: %s", strerror(-err));
+		goto failed;
+	}
+
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE_STREAM,
+							AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE_STREAM,
+							AUDIO_STATUS_FAILED);
+}
+
+static void bt_stream_resume(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_resume_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
+
+	DBG("");
+
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	if (setup->state != HAL_AUDIO_STARTED) {
+		err = avdtp_start(setup->dev->session, setup->stream);
+		if (err < 0) {
+			error("avdtp_start: %s", strerror(-err));
+			goto failed;
+		}
+	}
+
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_RESUME_STREAM,
+							AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_RESUME_STREAM,
+							AUDIO_STATUS_FAILED);
+}
+
+static void bt_stream_suspend(const void *buf, uint16_t len)
+{
+	const struct audio_cmd_suspend_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
+
+	DBG("");
+
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	err = avdtp_suspend(setup->dev->session, setup->stream);
+	if (err < 0) {
+		error("avdtp_suspend: %s", strerror(-err));
+		goto failed;
+	}
+
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_SUSPEND_STREAM,
+							AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
+	ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_SUSPEND_STREAM,
+							AUDIO_STATUS_FAILED);
+}
+
+static const struct ipc_handler audio_handlers[] = {
+	/* AUDIO_OP_OPEN */
+	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
+	/* AUDIO_OP_CLOSE */
+	{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
+	/* AUDIO_OP_OPEN_STREAM */
+	{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
+	/* AUDIO_OP_CLOSE_STREAM */
+	{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
+	/* AUDIO_OP_RESUME_STREAM */
+	{ bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
+	/* AUDIO_OP_SUSPEND_STREAM */
+	{ bt_stream_suspend, false, sizeof(struct audio_cmd_suspend_stream) },
+};
+
+static void bt_audio_unregister(void)
+{
+	DBG("");
+
+	if (audio_retry_id > 0)
+		g_source_remove(audio_retry_id);
+
+	g_slist_free_full(endpoints, unregister_endpoint);
+	endpoints = NULL;
+
+	g_slist_free_full(setups, setup_free);
+	setups = NULL;
+
+	ipc_cleanup(audio_ipc);
+	audio_ipc = NULL;
+
+	queue_destroy(lseps, NULL);
+}
+
+static bool bt_audio_register(ipc_disconnect_cb disconnect)
+{
+	DBG("");
+
+	audio_ipc = ipc_init(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+				AUDIO_SERVICE_ID_MAX, false, disconnect, NULL);
+	if (!audio_ipc)
+		return false;
+
+	ipc_register(audio_ipc, AUDIO_SERVICE_ID, audio_handlers,
+						G_N_ELEMENTS(audio_handlers));
+
+	return true;
+}
+
+static gboolean audio_retry_register(void *data)
+{
+	ipc_disconnect_cb cb = data;
+
+	audio_retry_id = 0;
+	audio_retrying = true;
+
+	bt_audio_register(cb);
+
+	return FALSE;
+}
+
+static void audio_disconnected(void *data)
+{
+	GSList *l;
+	bool restart;
+
+	DBG("");
+
+	if (audio_retrying)
+		goto retry;
+
+	restart = endpoints != NULL ? true : false;
+
+	bt_audio_unregister();
+
+	for (l = devices; l; l = g_slist_next(l)) {
+		struct a2dp_device *dev = l->data;
+
+		avdtp_shutdown(dev->session);
+	}
+
+	if (!restart)
+		return;
+
+retry:
+	audio_retry_id = g_timeout_add_seconds(AUDIO_RETRY_TIMEOUT,
+						audio_retry_register,
+						audio_disconnected);
+}
+
+bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
+{
+	GError *err = NULL;
+	sdp_record_t *rec;
+
+	DBG("");
+
+	bacpy(&adapter_addr, addr);
+
+	lseps = queue_new();
+
+	server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+				BT_IO_OPT_PSM, AVDTP_PSM,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_MASTER, true,
+				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 (!rec) {
+		error("Failed to allocate A2DP record");
+		goto fail;
+	}
+
+	if (bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
+		error("Failed to register A2DP record");
+		sdp_record_free(rec);
+		goto fail;
+	}
+	record_id = rec->handle;
+
+	hal_ipc = ipc;
+
+	ipc_register(hal_ipc, HAL_SERVICE_ID_A2DP, cmd_handlers,
+						G_N_ELEMENTS(cmd_handlers));
+
+	if (bt_audio_register(audio_disconnected))
+		return true;
+
+fail:
+	g_io_channel_shutdown(server, TRUE, NULL);
+	g_io_channel_unref(server);
+	server = NULL;
+	return false;
+}
+
+void bt_a2dp_unregister(void)
+{
+	DBG("");
+
+	g_slist_free_full(setups, setup_free);
+	setups = NULL;
+
+	g_slist_free_full(endpoints, unregister_endpoint);
+	endpoints = NULL;
+
+	g_slist_free_full(devices, a2dp_device_free);
+	devices = NULL;
+
+	ipc_unregister(hal_ipc, HAL_SERVICE_ID_A2DP);
+	hal_ipc = NULL;
+
+	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;
+	}
+
+	if (audio_ipc) {
+		ipc_unregister(audio_ipc, AUDIO_SERVICE_ID);
+		ipc_cleanup(audio_ipc);
+		audio_ipc = NULL;
+	}
+}
diff --git a/repo/android/a2dp.h b/repo/android/a2dp.h
new file mode 100644
index 0000000..8a70407
--- /dev/null
+++ b/repo/android/a2dp.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013-2014  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
+ *
+ */
+
+bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
+void bt_a2dp_unregister(void);
diff --git a/repo/android/audio-ipc-api.txt b/repo/android/audio-ipc-api.txt
new file mode 100644
index 0000000..f4a497d
--- /dev/null
+++ b/repo/android/audio-ipc-api.txt
@@ -0,0 +1,87 @@
+Bluetooth Audio Plugin
+======================
+
+The audio plugin happen to be in a different socket but all the rules for
+HAL socket apply here as well, the abstract socket name is
+"\0bluez_audio_socket" (tentative):
+
+	.---Audio---.                             .--Android--.
+	|  Plugin   |                             |   Daemon  |
+	|           |          Command            |           |
+	|           | --------------------------> |           |
+	|           |                             |           |
+	|           | <-------------------------- |           |
+	|           |          Response           |           |
+	|           |                             |           |
+	|           |                             |           |
+	|           |                             |           |
+	'-----------'                             '-----------'
+
+
+	Audio HAL                               Daemon
+	----------------------------------------------------
+
+	call dev->open()                    --> command 0x01
+	return dev->open()                  <-- response 0x01
+
+	call dev->open_output_stream()      --> command 0x03
+	return dev->open_output_stream()    <-- response 0x03
+
+	call stream->write()                --> command 0x05
+	return stream->write()              <-- response 0x05
+
+	call stream->common.standby()       --> command 0x06
+	return stream->common.standby()     <-- response 0x06
+
+	call dev->close_output_stream()     --> command 0x04
+	return dev->close_output_stream()   <-- response 0x04
+
+	call dev->close()                   --> command 0x02
+	return dev->close()                 <-- response 0x02
+
+Audio Service (ID 0)
+====================
+
+	Opcode 0x00 - Error response
+
+		Response parameters: Status (1 octet)
+
+	Opcode 0x01 - Open Audio Endpoint commmand
+
+		Command parameters: Service UUID (16 octets)
+				    Codec ID (1 octet)
+				    Number of codec presets (1 octet)
+				    Codec capabilities length (1 octet)
+				    Codec capabilities (variable)
+				    Codec preset # length (1 octet)
+				    Codec preset # configuration (variable)
+				    ...
+		Response parameters: Endpoint ID (1 octet)
+
+	Opcode 0x02 - Close Audio Endpoint command
+
+		Command parameters: Endpoint ID (1 octet)
+		Response parameters: <none>
+
+	Opcode 0x03 - Open Stream command
+
+		Command parameters: Endpoint ID (1 octet)
+		Response parameters: Outgoing MTU (2 octets)
+				     Codec configuration length (1 octet)
+				     Codec configuration (1 octet)
+				     File descriptor (inline)
+
+	Opcode 0x04 - Close Stream command
+
+		Command parameters: Endpoint ID (1 octet)
+		Response parameters: <none>
+
+	Opcode 0x05 - Resume Stream command
+
+		Command parameters: Endpoint ID (1 octet)
+		Response parameters: <none>
+
+	Opcode 0x06 - Suspend Stream command
+
+		Command parameters: Endpoint ID (1 octet)
+		Response parameters: <none>
diff --git a/repo/android/audio-msg.h b/repo/android/audio-msg.h
new file mode 100644
index 0000000..7b9553b
--- /dev/null
+++ b/repo/android/audio-msg.h
@@ -0,0 +1,82 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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_AUDIO_MTU 1024
+
+static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
+
+#define AUDIO_SERVICE_ID		0
+#define AUDIO_SERVICE_ID_MAX		AUDIO_SERVICE_ID
+
+#define AUDIO_STATUS_SUCCESS		IPC_STATUS_SUCCESS
+#define AUDIO_STATUS_FAILED		0x01
+
+#define AUDIO_OP_STATUS			IPC_OP_STATUS
+
+#define AUDIO_OP_OPEN			0x01
+struct audio_preset {
+	uint8_t len;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_cmd_open {
+	uint8_t uuid[16];
+	uint8_t codec;
+	uint8_t presets;
+	struct audio_preset preset[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+	uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE			0x02
+struct audio_cmd_close {
+	uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_OPEN_STREAM		0x03
+struct audio_cmd_open_stream {
+	uint8_t id;
+} __attribute__((packed));
+
+struct audio_rsp_open_stream {
+	uint16_t id;
+	uint16_t mtu;
+	struct audio_preset preset[0];
+} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE_STREAM		0x04
+struct audio_cmd_close_stream {
+	uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_RESUME_STREAM		0x05
+struct audio_cmd_resume_stream {
+	uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_SUSPEND_STREAM		0x06
+struct audio_cmd_suspend_stream {
+	uint8_t id;
+} __attribute__((packed));
diff --git a/repo/android/audio_utils/resampler.c b/repo/android/audio_utils/resampler.c
new file mode 100644
index 0000000..ce30375
--- /dev/null
+++ b/repo/android/audio_utils/resampler.c
@@ -0,0 +1,270 @@
+/*
+** Copyright 2011, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <speex/speex_resampler.h>
+
+#include "hal-log.h"
+
+struct resampler {
+    struct resampler_itfe itfe;
+    SpeexResamplerState *speex_resampler;       // handle on speex resampler
+    struct resampler_buffer_provider *provider; // buffer provider installed by client
+    uint32_t in_sample_rate;                    // input sampling rate in Hz
+    uint32_t out_sample_rate;                   // output sampling rate in Hz
+    uint32_t channel_count;                     // number of channels (interleaved)
+    int16_t *in_buf;                            // input buffer
+    size_t in_buf_size;                         // input buffer size
+    size_t frames_in;                           // number of frames in input buffer
+    size_t frames_rq;                           // cached number of output frames
+    size_t frames_needed;                       // minimum number of input frames to produce
+                                                // frames_rq output frames
+    int32_t speex_delay_ns;                     // delay introduced by speex resampler in ns
+};
+
+
+//------------------------------------------------------------------------------
+// speex based resampler
+//------------------------------------------------------------------------------
+
+static void resampler_reset(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    rsmp->frames_in = 0;
+    rsmp->frames_rq = 0;
+
+    if (rsmp != NULL && rsmp->speex_resampler != NULL) {
+        speex_resampler_reset_mem(rsmp->speex_resampler);
+    }
+}
+
+static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
+    delay += rsmp->speex_delay_ns;
+
+    return delay;
+}
+
+// outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount
+// with the actual number of frames produced.
+static int resampler_resample_from_provider(struct resampler_itfe *resampler,
+                       int16_t *out,
+                       size_t *outFrameCount)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+    size_t framesRq;
+    size_t framesWr;
+    size_t inFrames;
+
+    if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
+        return -EINVAL;
+    }
+    if (rsmp->provider == NULL) {
+        *outFrameCount = 0;
+        return -ENOSYS;
+    }
+
+    framesRq = *outFrameCount;
+    // update and cache the number of frames needed at the input sampling rate to produce
+    // the number of frames requested at the output sampling rate
+    if (framesRq != rsmp->frames_rq) {
+        rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
+        rsmp->frames_rq = framesRq;
+    }
+
+    framesWr = 0;
+    inFrames = 0;
+    while (framesWr < framesRq) {
+        size_t outFrames;
+        if (rsmp->frames_in < rsmp->frames_needed) {
+            struct resampler_buffer buf;
+            // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
+            // least the number of frames needed to produce the number of frames requested at
+            // the output sampling rate
+            if (rsmp->in_buf_size < rsmp->frames_needed) {
+                rsmp->in_buf_size = rsmp->frames_needed;
+                rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
+                                        rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
+            }
+            buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
+            rsmp->provider->get_next_buffer(rsmp->provider, &buf);
+            if (buf.raw == NULL) {
+                break;
+            }
+            memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
+                    buf.raw,
+                    buf.frame_count * rsmp->channel_count * sizeof(int16_t));
+            rsmp->frames_in += buf.frame_count;
+            rsmp->provider->release_buffer(rsmp->provider, &buf);
+        }
+
+        outFrames = framesRq - framesWr;
+        inFrames = rsmp->frames_in;
+        if (rsmp->channel_count == 1) {
+            speex_resampler_process_int(rsmp->speex_resampler,
+                                        0,
+                                        rsmp->in_buf,
+                                        (void *) &inFrames,
+                                        out + framesWr,
+                                        (void *) &outFrames);
+        } else {
+            speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+                                        rsmp->in_buf,
+                                        (void *) &inFrames,
+                                        out + framesWr * rsmp->channel_count,
+                                        (void *) &outFrames);
+        }
+        framesWr += outFrames;
+        rsmp->frames_in -= inFrames;
+
+        if ((framesWr != framesRq) && (rsmp->frames_in != 0))
+            warn("ReSampler::resample() remaining %zd frames in and %zd out",
+                rsmp->frames_in, (framesRq - framesWr));
+    }
+    if (rsmp->frames_in) {
+        memmove(rsmp->in_buf,
+                rsmp->in_buf + inFrames * rsmp->channel_count,
+                rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
+    }
+    *outFrameCount = framesWr;
+
+    return 0;
+}
+
+static int resampler_resample_from_input(struct resampler_itfe *resampler,
+                                  int16_t *in,
+                                  size_t *inFrameCount,
+                                  int16_t *out,
+                                  size_t *outFrameCount)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
+            out == NULL || outFrameCount == NULL) {
+        return -EINVAL;
+    }
+    if (rsmp->provider != NULL) {
+        *outFrameCount = 0;
+        return -ENOSYS;
+    }
+
+    if (rsmp->channel_count == 1) {
+        speex_resampler_process_int(rsmp->speex_resampler,
+                                    0,
+                                    in,
+                                    (void *) inFrameCount,
+                                    out,
+                                    (void *) outFrameCount);
+    } else {
+        speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+                                                in,
+                                                (void *) inFrameCount,
+                                                out,
+                                                (void *) outFrameCount);
+    }
+
+    DBG("resampler_resample_from_input() DONE in %zd out %zd", *inFrameCount, *outFrameCount);
+
+    return 0;
+}
+
+int create_resampler(uint32_t inSampleRate,
+                    uint32_t outSampleRate,
+                    uint32_t channelCount,
+                    uint32_t quality,
+                    struct resampler_buffer_provider* provider,
+                    struct resampler_itfe **resampler)
+{
+    int error;
+    struct resampler *rsmp;
+    int frames;
+
+    DBG("create_resampler() In SR %d Out SR %d channels %d",
+         inSampleRate, outSampleRate, channelCount);
+
+    if (resampler == NULL) {
+        return -EINVAL;
+    }
+
+    *resampler = NULL;
+
+    if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
+        return -EINVAL;
+    }
+
+    rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
+
+    rsmp->speex_resampler = speex_resampler_init(channelCount,
+                                      inSampleRate,
+                                      outSampleRate,
+                                      quality,
+                                      &error);
+    if (rsmp->speex_resampler == NULL) {
+        error("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
+        free(rsmp);
+        return -ENODEV;
+    }
+
+    rsmp->itfe.reset = resampler_reset;
+    rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
+    rsmp->itfe.resample_from_input = resampler_resample_from_input;
+    rsmp->itfe.delay_ns = resampler_delay_ns;
+
+    rsmp->provider = provider;
+    rsmp->in_sample_rate = inSampleRate;
+    rsmp->out_sample_rate = outSampleRate;
+    rsmp->channel_count = channelCount;
+    rsmp->in_buf = NULL;
+    rsmp->in_buf_size = 0;
+
+    resampler_reset(&rsmp->itfe);
+
+    frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
+    rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
+    frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
+    rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
+
+    *resampler = &rsmp->itfe;
+    DBG("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
+         rsmp, &rsmp->itfe, rsmp->speex_resampler);
+    return 0;
+}
+
+void release_resampler(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    if (rsmp == NULL) {
+        return;
+    }
+
+    free(rsmp->in_buf);
+
+    if (rsmp->speex_resampler != NULL) {
+        speex_resampler_destroy(rsmp->speex_resampler);
+    }
+    free(rsmp);
+}
diff --git a/repo/android/audio_utils/resampler.h b/repo/android/audio_utils/resampler.h
new file mode 100644
index 0000000..0c7046f
--- /dev/null
+++ b/repo/android/audio_utils/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 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_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+    union {
+        void*       raw;
+        short*      i16;
+        int8_t*     i8;
+    };
+    size_t frame_count;
+};
+
+/* call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+    /**
+     *  get a new buffer of data:
+     *   as input: buffer->frame_count is the number of frames requested
+     *   as output: buffer->frame_count is the number of frames returned
+     *              buffer->raw points to data returned
+     */
+    int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+            struct resampler_buffer *buffer);
+    /**
+     *  release a consumed buffer of data:
+     *   as input: buffer->frame_count is the number of frames released
+     *             buffer->raw points to data released
+     */
+    void (*release_buffer)(struct resampler_buffer_provider *provider,
+            struct resampler_buffer *buffer);
+};
+
+/* resampler interface */
+struct resampler_itfe {
+    /**
+     * reset resampler state
+     */
+    void (*reset)(struct resampler_itfe *resampler);
+    /**
+     * resample input from buffer provider and output at most *outFrameCount to out buffer.
+     * *outFrameCount is updated with the actual number of frames produced.
+     */
+    int (*resample_from_provider)(struct resampler_itfe *resampler,
+                    int16_t *out,
+                    size_t *outFrameCount);
+    /**
+     * resample at most *inFrameCount frames from in buffer and output at most
+     * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+     * with the number of frames remaining in input and written to output.
+     */
+    int (*resample_from_input)(struct resampler_itfe *resampler,
+                    int16_t *in,
+                    size_t *inFrameCount,
+                    int16_t *out,
+                    size_t *outFrameCount);
+    /**
+     * return the latency introduced by the resampler in ns.
+     */
+    int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+          uint32_t outSampleRate,
+          uint32_t channelCount,
+          uint32_t quality,
+          struct resampler_buffer_provider *provider,
+          struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/repo/android/avctp.c b/repo/android/avctp.c
new file mode 100644
index 0000000..6aa64cf
--- /dev/null
+++ b/repo/android/avctp.c
@@ -0,0 +1,1653 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  Texas Instruments, Inc.
+ *
+ *
+ *  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 <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+
+#include "lib/sdp.h"
+
+#include "src/log.h"
+#include "src/uinput.h"
+
+#include "avctp.h"
+
+/*
+ * AV/C Panel 1.23, page 76:
+ * command with the pressed value is valid for two seconds
+ */
+#define AVC_PRESS_TIMEOUT	2
+
+#define QUIRK_NO_RELEASE 1 << 0
+
+/* Message types */
+#define AVCTP_COMMAND		0
+#define AVCTP_RESPONSE		1
+
+/* Packet types */
+#define AVCTP_PACKET_SINGLE	0
+#define AVCTP_PACKET_START	1
+#define AVCTP_PACKET_CONTINUE	2
+#define AVCTP_PACKET_END	3
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avctp_header {
+	uint8_t ipid:1;
+	uint8_t cr:1;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint16_t pid;
+} __attribute__ ((packed));
+
+struct avc_header {
+	uint8_t code:4;
+	uint8_t _hdr0:4;
+	uint8_t subunit_id:3;
+	uint8_t subunit_type:5;
+	uint8_t opcode;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avctp_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t cr:1;
+	uint8_t ipid:1;
+	uint16_t pid;
+} __attribute__ ((packed));
+
+struct avc_header {
+	uint8_t _hdr0:4;
+	uint8_t code:4;
+	uint8_t subunit_type:5;
+	uint8_t subunit_id:3;
+	uint8_t opcode;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avctp_control_req {
+	struct avctp_pending_req *p;
+	uint8_t code;
+	uint8_t subunit;
+	uint8_t op;
+	struct iovec *iov;
+	int iov_cnt;
+	avctp_rsp_cb func;
+	void *user_data;
+};
+
+struct avctp_browsing_req {
+	struct avctp_pending_req *p;
+	struct iovec *iov;
+	int iov_cnt;
+	avctp_browsing_rsp_cb func;
+	void *user_data;
+};
+
+typedef int (*avctp_process_cb) (void *data);
+
+struct avctp_pending_req {
+	struct avctp_channel *chan;
+	uint8_t transaction;
+	guint timeout;
+	int err;
+	avctp_process_cb process;
+	void *data;
+	avctp_destroy_cb_t destroy;
+};
+
+struct avctp_channel {
+	struct avctp *session;
+	GIOChannel *io;
+	uint8_t transaction;
+	guint watch;
+	uint16_t imtu;
+	uint16_t omtu;
+	uint8_t *buffer;
+	GSList *handlers;
+	struct avctp_pending_req *p;
+	GQueue *queue;
+	GSList *processed;
+	guint process_id;
+	avctp_destroy_cb_t destroy;
+};
+
+struct key_pressed {
+	uint8_t op;
+	uint8_t *params;
+	size_t params_len;
+	guint timer;
+};
+
+struct avctp {
+	unsigned int ref;
+	int uinput;
+
+	unsigned int passthrough_id;
+	unsigned int unit_id;
+	unsigned int subunit_id;
+
+	struct avctp_channel *control;
+	struct avctp_channel *browsing;
+
+	struct avctp_passthrough_handler *handler;
+
+	uint8_t key_quirks[256];
+	struct key_pressed key;
+	uint16_t version;
+
+	avctp_destroy_cb_t destroy;
+	void *data;
+};
+
+struct avctp_passthrough_handler {
+	avctp_passthrough_cb cb;
+	void *user_data;
+	unsigned int id;
+};
+
+struct avctp_pdu_handler {
+	uint8_t opcode;
+	avctp_control_pdu_cb cb;
+	void *user_data;
+	unsigned int id;
+};
+
+struct avctp_browsing_pdu_handler {
+	avctp_browsing_pdu_cb cb;
+	void *user_data;
+	unsigned int id;
+	avctp_destroy_cb_t destroy;
+};
+
+static struct {
+	const char *name;
+	uint8_t avc;
+	uint16_t uinput;
+} key_map[] = {
+	{ "SELECT",		AVC_SELECT,		KEY_SELECT },
+	{ "UP",			AVC_UP,			KEY_UP },
+	{ "DOWN",		AVC_DOWN,		KEY_DOWN },
+	{ "LEFT",		AVC_LEFT,		KEY_LEFT },
+	{ "RIGHT",		AVC_RIGHT,		KEY_RIGHT },
+	{ "ROOT MENU",		AVC_ROOT_MENU,		KEY_MENU },
+	{ "CONTENTS MENU",	AVC_CONTENTS_MENU,	KEY_PROGRAM },
+	{ "FAVORITE MENU",	AVC_FAVORITE_MENU,	KEY_FAVORITES },
+	{ "EXIT",		AVC_EXIT,		KEY_EXIT },
+	{ "ON DEMAND MENU",	AVC_ON_DEMAND_MENU,	KEY_MENU },
+	{ "APPS MENU",		AVC_APPS_MENU,		KEY_MENU },
+	{ "0",			AVC_0,			KEY_0 },
+	{ "1",			AVC_1,			KEY_1 },
+	{ "2",			AVC_2,			KEY_2 },
+	{ "3",			AVC_3,			KEY_3 },
+	{ "4",			AVC_4,			KEY_4 },
+	{ "5",			AVC_5,			KEY_5 },
+	{ "6",			AVC_6,			KEY_6 },
+	{ "7",			AVC_7,			KEY_7 },
+	{ "8",			AVC_8,			KEY_8 },
+	{ "9",			AVC_9,			KEY_9 },
+	{ "DOT",		AVC_DOT,		KEY_DOT },
+	{ "ENTER",		AVC_ENTER,		KEY_ENTER },
+	{ "CHANNEL UP",		AVC_CHANNEL_UP,		KEY_CHANNELUP },
+	{ "CHANNEL DOWN",	AVC_CHANNEL_DOWN,	KEY_CHANNELDOWN },
+	{ "CHANNEL PREVIOUS",	AVC_CHANNEL_PREVIOUS,	KEY_LAST },
+	{ "INPUT SELECT",	AVC_INPUT_SELECT,	KEY_CONFIG },
+	{ "INFO",		AVC_INFO,		KEY_INFO },
+	{ "HELP",		AVC_HELP,		KEY_HELP },
+	{ "POWER",		AVC_POWER,		KEY_POWER2 },
+	{ "VOLUME UP",		AVC_VOLUME_UP,		KEY_VOLUMEUP },
+	{ "VOLUME DOWN",	AVC_VOLUME_DOWN,	KEY_VOLUMEDOWN },
+	{ "MUTE",		AVC_MUTE,		KEY_MUTE },
+	{ "PLAY",		AVC_PLAY,		KEY_PLAYCD },
+	{ "STOP",		AVC_STOP,		KEY_STOPCD },
+	{ "PAUSE",		AVC_PAUSE,		KEY_PAUSECD },
+	{ "FORWARD",		AVC_FORWARD,		KEY_NEXTSONG },
+	{ "BACKWARD",		AVC_BACKWARD,		KEY_PREVIOUSSONG },
+	{ "RECORD",		AVC_RECORD,		KEY_RECORD },
+	{ "REWIND",		AVC_REWIND,		KEY_REWIND },
+	{ "FAST FORWARD",	AVC_FAST_FORWARD,	KEY_FASTFORWARD },
+	{ "LIST",		AVC_LIST,		KEY_LIST },
+	{ "F1",			AVC_F1,			KEY_F1 },
+	{ "F2",			AVC_F2,			KEY_F2 },
+	{ "F3",			AVC_F3,			KEY_F3 },
+	{ "F4",			AVC_F4,			KEY_F4 },
+	{ "F5",			AVC_F5,			KEY_F5 },
+	{ "F6",			AVC_F6,			KEY_F6 },
+	{ "F7",			AVC_F7,			KEY_F7 },
+	{ "F8",			AVC_F8,			KEY_F8 },
+	{ "F9",			AVC_F9,			KEY_F9 },
+	{ "RED",		AVC_RED,		KEY_RED },
+	{ "GREEN",		AVC_GREEN,		KEY_GREEN },
+	{ "BLUE",		AVC_BLUE,		KEY_BLUE },
+	{ "YELLOW",		AVC_YELLOW,		KEY_YELLOW },
+	{ NULL }
+};
+
+static gboolean process_queue(gpointer user_data);
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+					uint8_t subunit, uint8_t *operands,
+					size_t operand_count, void *user_data);
+
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+	struct uinput_event event;
+	int err;
+
+	memset(&event, 0, sizeof(event));
+	event.type	= type;
+	event.code	= code;
+	event.value	= value;
+
+	do {
+		err = write(fd, &event, sizeof(event));
+	} while (err < 0 && errno == EINTR);
+
+	if (err < 0) {
+		err = -errno;
+		error("send_event: %s (%d)", strerror(-err), -err);
+	}
+
+	return err;
+}
+
+static void send_key(int fd, uint16_t key, int pressed)
+{
+	send_event(fd, EV_KEY, key, pressed);
+	send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static gboolean auto_release(gpointer user_data)
+{
+	struct avctp *session = user_data;
+
+	session->key.timer = 0;
+
+	DBG("AV/C: key press timeout");
+
+	send_key(session->uinput, session->key.op, 0);
+
+	return FALSE;
+}
+
+static ssize_t handle_panel_passthrough(struct avctp *session,
+					uint8_t transaction, uint8_t *code,
+					uint8_t *subunit, uint8_t *operands,
+					size_t operand_count, void *user_data)
+{
+	struct avctp_passthrough_handler *handler = session->handler;
+	const char *status;
+	int pressed, i;
+
+	if (*code != AVC_CTYPE_CONTROL || *subunit != AVC_SUBUNIT_PANEL) {
+		*code = AVC_CTYPE_REJECTED;
+		return operand_count;
+	}
+
+	if (operand_count == 0)
+		goto done;
+
+	if (operands[0] & 0x80) {
+		status = "released";
+		pressed = 0;
+	} else {
+		status = "pressed";
+		pressed = 1;
+	}
+
+	if (session->key.timer == 0 && handler != NULL) {
+		if (handler->cb(session, operands[0] & 0x7F,
+						pressed, handler->user_data))
+			goto done;
+	}
+
+	if (session->uinput < 0) {
+		DBG("AV/C: uinput not initialized");
+		*code = AVC_CTYPE_NOT_IMPLEMENTED;
+		return 0;
+	}
+
+	for (i = 0; key_map[i].name != NULL; i++) {
+		uint8_t key_quirks;
+
+		if ((operands[0] & 0x7F) != key_map[i].avc)
+			continue;
+
+		DBG("AV/C: %s %s", key_map[i].name, status);
+
+		key_quirks = session->key_quirks[key_map[i].avc];
+
+		if (key_quirks & QUIRK_NO_RELEASE) {
+			if (!pressed) {
+				DBG("AV/C: Ignoring release");
+				break;
+			}
+
+			DBG("AV/C: treating key press as press + release");
+			send_key(session->uinput, key_map[i].uinput, 1);
+			send_key(session->uinput, key_map[i].uinput, 0);
+			break;
+		}
+
+		if (pressed) {
+			if (session->key.timer > 0) {
+				g_source_remove(session->key.timer);
+				send_key(session->uinput, session->key.op, 0);
+			}
+
+			session->key.op = key_map[i].uinput;
+			session->key.timer = g_timeout_add_seconds(
+							AVC_PRESS_TIMEOUT,
+							auto_release,
+							session);
+		} else if (session->key.timer > 0) {
+			g_source_remove(session->key.timer);
+			session->key.timer = 0;
+		}
+
+		send_key(session->uinput, key_map[i].uinput, pressed);
+		break;
+	}
+
+	if (key_map[i].name == NULL) {
+		DBG("AV/C: unknown button 0x%02X %s",
+						operands[0] & 0x7F, status);
+		*code = AVC_CTYPE_NOT_IMPLEMENTED;
+		return operand_count;
+	}
+
+done:
+	*code = AVC_CTYPE_ACCEPTED;
+	return operand_count;
+}
+
+static ssize_t handle_unit_info(struct avctp *session,
+					uint8_t transaction, uint8_t *code,
+					uint8_t *subunit, uint8_t *operands,
+					size_t operand_count, void *user_data)
+{
+	if (*code != AVC_CTYPE_STATUS) {
+		*code = AVC_CTYPE_REJECTED;
+		return 0;
+	}
+
+	*code = AVC_CTYPE_STABLE;
+
+	/*
+	 * The first operand should be 0x07 for the UNITINFO response.
+	 * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+	 * Interface Command Set (section 9.2.1, page 45) specs
+	 * explain this value but both use it
+	 */
+	if (operand_count >= 1)
+		operands[0] = 0x07;
+	if (operand_count >= 2)
+		operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+	DBG("reply to AVC_OP_UNITINFO");
+
+	return operand_count;
+}
+
+static ssize_t handle_subunit_info(struct avctp *session,
+					uint8_t transaction, uint8_t *code,
+					uint8_t *subunit, uint8_t *operands,
+					size_t operand_count, void *user_data)
+{
+	if (*code != AVC_CTYPE_STATUS) {
+		*code = AVC_CTYPE_REJECTED;
+		return 0;
+	}
+
+	*code = AVC_CTYPE_STABLE;
+
+	/*
+	 * The first operand should be 0x07 for the UNITINFO response.
+	 * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+	 * Interface Command Set (section 9.2.1, page 45) specs
+	 * explain this value but both use it
+	 */
+	if (operand_count >= 2)
+		operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+	DBG("reply to AVC_OP_SUBUNITINFO");
+
+	return operand_count;
+}
+
+static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
+{
+	for (; list; list = list->next) {
+		struct avctp_pdu_handler *handler = list->data;
+
+		if (handler->opcode == opcode)
+			return handler;
+	}
+
+	return NULL;
+}
+
+static void pending_destroy(gpointer data, gpointer user_data)
+{
+	struct avctp_pending_req *req = data;
+
+	if (req->destroy)
+		req->destroy(req->data);
+
+	if (req->timeout > 0)
+		g_source_remove(req->timeout);
+
+	g_free(req);
+}
+
+static void avctp_channel_destroy(struct avctp_channel *chan)
+{
+	g_io_channel_shutdown(chan->io, TRUE, NULL);
+	g_io_channel_unref(chan->io);
+
+	if (chan->watch)
+		g_source_remove(chan->watch);
+
+	if (chan->p)
+		pending_destroy(chan->p, NULL);
+
+	if (chan->process_id > 0)
+		g_source_remove(chan->process_id);
+
+	if (chan->destroy)
+		chan->destroy(chan);
+
+	g_free(chan->buffer);
+	g_queue_foreach(chan->queue, pending_destroy, NULL);
+	g_queue_free(chan->queue);
+	g_slist_foreach(chan->processed, pending_destroy, NULL);
+	g_slist_free(chan->processed);
+	g_slist_free_full(chan->handlers, g_free);
+	g_free(chan);
+}
+
+static int avctp_send(struct avctp_channel *control, uint8_t transaction,
+				uint8_t cr, uint8_t code,
+				uint8_t subunit, uint8_t opcode,
+				const struct iovec *iov, int iov_cnt)
+{
+	struct avctp_header avctp;
+	struct avc_header avc;
+	struct msghdr msg;
+	int sk, err = 0;
+	struct iovec pdu[iov_cnt + 2];
+	int i;
+	size_t len = sizeof(avctp) + sizeof(avc);
+
+	DBG("");
+
+	pdu[0].iov_base = &avctp;
+	pdu[0].iov_len  = sizeof(avctp);
+	pdu[1].iov_base = &avc;
+	pdu[1].iov_len  = sizeof(avc);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i + 2].iov_base = iov[i].iov_base;
+		pdu[i + 2].iov_len  = iov[i].iov_len;
+		len += iov[i].iov_len;
+	}
+
+	if (control->omtu < len)
+		return -EOVERFLOW;
+
+	sk = g_io_channel_unix_get_fd(control->io);
+
+	memset(&avctp, 0, sizeof(avctp));
+
+	avctp.transaction = transaction;
+	avctp.packet_type = AVCTP_PACKET_SINGLE;
+	avctp.cr = cr;
+	avctp.pid = htons(AV_REMOTE_SVCLASS_ID);
+
+	memset(&avc, 0, sizeof(avc));
+
+	avc.code = code;
+	avc.subunit_type = subunit;
+	avc.opcode = opcode;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = pdu;
+	msg.msg_iovlen = iov_cnt + 2;
+
+	if (sendmsg(sk, &msg, 0) < 0)
+		err = -errno;
+
+	return err;
+}
+
+static int avctp_browsing_send(struct avctp_channel *browsing,
+				uint8_t transaction, uint8_t cr,
+				const struct iovec *iov, int iov_cnt)
+{
+	struct avctp_header avctp;
+	struct msghdr msg;
+	struct iovec pdu[iov_cnt + 1];
+	int sk, err = 0;
+	int i;
+	size_t len = sizeof(avctp);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i + 1].iov_base = iov[i].iov_base;
+		pdu[i + 1].iov_len  = iov[i].iov_len;
+		len += iov[i].iov_len;
+	}
+
+	pdu[0].iov_base = &avctp;
+	pdu[0].iov_len  = sizeof(avctp);
+
+	if (browsing->omtu < len)
+		return -EOVERFLOW;
+
+	sk = g_io_channel_unix_get_fd(browsing->io);
+
+	memset(&avctp, 0, sizeof(avctp));
+
+	avctp.transaction = transaction;
+	avctp.packet_type = AVCTP_PACKET_SINGLE;
+	avctp.cr = cr;
+	avctp.pid = htons(AV_REMOTE_SVCLASS_ID);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = pdu;
+	msg.msg_iovlen = iov_cnt + 1;
+
+	if (sendmsg(sk, &msg, 0) < 0)
+		err = -errno;
+
+	return err;
+}
+
+static void control_req_destroy(void *data)
+{
+	struct avctp_control_req *req = data;
+	struct avctp_pending_req *p = req->p;
+	struct avctp *session = p->chan->session;
+	int i;
+
+	if (p->err == 0 || req->func == NULL)
+		goto done;
+
+	req->func(session, AVC_CTYPE_REJECTED, req->subunit, NULL, 0,
+							req->user_data);
+
+done:
+	for (i = 0; i < req->iov_cnt; i++)
+		g_free(req->iov[i].iov_base);
+
+	g_free(req->iov);
+	g_free(req);
+}
+
+static void browsing_req_destroy(void *data)
+{
+	struct avctp_browsing_req *req = data;
+	struct avctp_pending_req *p = req->p;
+	struct avctp *session = p->chan->session;
+	int i;
+
+	if (p->err == 0 || req->func == NULL)
+		goto done;
+
+	req->func(session, NULL, 0, req->user_data);
+
+done:
+	for (i = 0; i < req->iov_cnt; i++)
+		g_free(req->iov[i].iov_base);
+
+	g_free(req->iov);
+	g_free(req);
+}
+
+static gboolean req_timeout(gpointer user_data)
+{
+	struct avctp_channel *chan = user_data;
+	struct avctp_pending_req *p = chan->p;
+
+	DBG("transaction %u", p->transaction);
+
+	p->timeout = 0;
+	p->err = -ETIMEDOUT;
+
+	pending_destroy(p, NULL);
+	chan->p = NULL;
+
+	if (chan->process_id == 0)
+		chan->process_id = g_idle_add(process_queue, chan);
+
+	return FALSE;
+}
+
+static int process_control(void *data)
+{
+	struct avctp_control_req *req = data;
+	struct avctp_pending_req *p = req->p;
+
+	return avctp_send(p->chan, p->transaction, AVCTP_COMMAND, req->code,
+				req->subunit, req->op, req->iov, req->iov_cnt);
+}
+
+static int process_browsing(void *data)
+{
+	struct avctp_browsing_req *req = data;
+	struct avctp_pending_req *p = req->p;
+
+	return avctp_browsing_send(p->chan, p->transaction, AVCTP_COMMAND,
+						req->iov, req->iov_cnt);
+}
+
+static gboolean process_queue(void *user_data)
+{
+	struct avctp_channel *chan = user_data;
+	struct avctp_pending_req *p = chan->p;
+
+	chan->process_id = 0;
+
+	if (p != NULL)
+		return FALSE;
+
+	while ((p = g_queue_pop_head(chan->queue))) {
+
+		if (p->process(p->data) == 0)
+			break;
+
+		pending_destroy(p, NULL);
+	}
+
+	if (p == NULL)
+		return FALSE;
+
+	chan->p = p;
+	p->timeout = g_timeout_add_seconds(2, req_timeout, chan);
+
+	return FALSE;
+
+}
+
+static struct avctp *avctp_ref(struct avctp *session)
+{
+	__sync_fetch_and_add(&session->ref, 1);
+
+	DBG("%p: ref=%d", session, session->ref);
+
+	return session;
+}
+
+static void avctp_unref(struct avctp *session)
+{
+	DBG("%p: ref=%d", session, session->ref);
+
+	if (__sync_sub_and_fetch(&session->ref, 1))
+		return;
+
+	if (session->browsing)
+		avctp_channel_destroy(session->browsing);
+
+	if (session->control)
+		avctp_channel_destroy(session->control);
+
+	if (session->destroy)
+		session->destroy(session->data);
+
+	g_free(session->handler);
+
+	if (session->key.timer > 0)
+		g_source_remove(session->key.timer);
+
+	if (session->uinput >= 0) {
+		DBG("AVCTP: closing uinput");
+
+		ioctl(session->uinput, UI_DEV_DESTROY);
+		close(session->uinput);
+		session->uinput = -1;
+	}
+
+	g_free(session);
+}
+
+static void control_response(struct avctp_channel *control,
+					struct avctp_header *avctp,
+					struct avc_header *avc,
+					uint8_t *operands,
+					size_t operand_count)
+{
+	struct avctp_pending_req *p = control->p;
+	struct avctp_control_req *req;
+	GSList *l;
+
+	if (p && p->transaction == avctp->transaction) {
+		control->processed = g_slist_prepend(control->processed, p);
+
+		if (p->timeout > 0) {
+			g_source_remove(p->timeout);
+			p->timeout = 0;
+		}
+
+		control->p = NULL;
+
+		if (control->process_id == 0)
+			control->process_id = g_idle_add(process_queue,
+								control);
+	}
+
+	avctp_ref(control->session);
+
+	for (l = control->processed; l; l = l->next) {
+		p = l->data;
+		req = p->data;
+
+		if (p->transaction != avctp->transaction)
+			continue;
+
+		if (req->func && req->func(control->session, avc->code,
+						avc->subunit_type,
+						operands, operand_count,
+						req->user_data))
+			break;
+
+		control->processed = g_slist_remove(control->processed, p);
+		pending_destroy(p, NULL);
+
+		break;
+	}
+
+	avctp_unref(control->session);
+}
+
+static void browsing_response(struct avctp_channel *browsing,
+					struct avctp_header *avctp,
+					uint8_t *operands,
+					size_t operand_count)
+{
+	struct avctp_pending_req *p = browsing->p;
+	struct avctp_browsing_req *req;
+	GSList *l;
+
+	if (p && p->transaction == avctp->transaction) {
+		browsing->processed = g_slist_prepend(browsing->processed, p);
+
+		if (p->timeout > 0) {
+			g_source_remove(p->timeout);
+			p->timeout = 0;
+		}
+
+		browsing->p = NULL;
+
+		if (browsing->process_id == 0)
+			browsing->process_id = g_idle_add(process_queue,
+								browsing);
+	}
+
+	avctp_ref(browsing->session);
+
+	for (l = browsing->processed; l; l = l->next) {
+		p = l->data;
+		req = p->data;
+
+		if (p->transaction != avctp->transaction)
+			continue;
+
+		if (req->func && req->func(browsing->session, operands,
+						operand_count, req->user_data))
+			break;
+
+		browsing->processed = g_slist_remove(browsing->processed, p);
+		pending_destroy(p, NULL);
+
+		break;
+	}
+
+	avctp_unref(browsing->session);
+}
+
+static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	struct avctp *session = data;
+	struct avctp_channel *browsing = session->browsing;
+	uint8_t *buf = browsing->buffer;
+	uint8_t *operands;
+	struct avctp_header *avctp;
+	int sock, ret, packet_size, operand_count;
+	struct avctp_browsing_pdu_handler *handler;
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		goto failed;
+
+	sock = g_io_channel_unix_get_fd(chan);
+
+	ret = read(sock, buf, browsing->imtu);
+	if (ret <= 0)
+		goto failed;
+
+	if (ret < AVCTP_HEADER_LENGTH) {
+		error("Too small AVCTP packet");
+		goto failed;
+	}
+
+	avctp = (struct avctp_header *) buf;
+
+	if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
+		error("Invalid packet type");
+		goto failed;
+	}
+
+	operands = buf + AVCTP_HEADER_LENGTH;
+	ret -= AVCTP_HEADER_LENGTH;
+	operand_count = ret;
+
+	if (avctp->cr == AVCTP_RESPONSE) {
+		browsing_response(browsing, avctp, operands, operand_count);
+		return TRUE;
+	}
+
+	packet_size = AVCTP_HEADER_LENGTH;
+	avctp->cr = AVCTP_RESPONSE;
+
+	handler = g_slist_nth_data(browsing->handlers, 0);
+	if (handler == NULL) {
+		DBG("handler not found");
+		/* FIXME: Add general reject */
+		/* packet_size += avrcp_browsing_general_reject(operands); */
+		goto send;
+	}
+
+	ret = handler->cb(session, avctp->transaction, operands, operand_count,
+							handler->user_data);
+	if (ret < 0) {
+		if (ret == -EAGAIN)
+			return TRUE;
+		goto failed;
+	}
+
+	packet_size += ret;
+
+send:
+	if (packet_size != 0) {
+		ret = write(sock, buf, packet_size);
+		if (ret != packet_size)
+			goto failed;
+	}
+
+	return TRUE;
+
+failed:
+	DBG("AVCTP Browsing: disconnected");
+
+	if (session->browsing) {
+		avctp_channel_destroy(session->browsing);
+		session->browsing = NULL;
+	}
+
+	return FALSE;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct avctp *session = data;
+	struct avctp_channel *control = session->control;
+	uint8_t *buf = control->buffer;
+	uint8_t *operands, code, subunit;
+	struct avctp_header *avctp;
+	struct avc_header *avc;
+	int packet_size, operand_count, sock;
+	struct avctp_pdu_handler *handler;
+	ssize_t ret;
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		goto failed;
+
+	sock = g_io_channel_unix_get_fd(chan);
+
+	ret = read(sock, buf, control->imtu);
+	if (ret <= 0)
+		goto failed;
+
+	if (ret < AVCTP_HEADER_LENGTH) {
+		error("Too small AVCTP packet");
+		goto failed;
+	}
+
+	avctp = (struct avctp_header *) buf;
+
+	ret -= AVCTP_HEADER_LENGTH;
+	if (ret < AVC_HEADER_LENGTH) {
+		error("Too small AVC packet");
+		goto failed;
+	}
+
+	avc = (struct avc_header *) (buf + AVCTP_HEADER_LENGTH);
+
+	ret -= AVC_HEADER_LENGTH;
+
+	operands = (uint8_t *) avc + AVC_HEADER_LENGTH;
+	operand_count = ret;
+
+	if (avctp->cr == AVCTP_RESPONSE) {
+		control_response(control, avctp, avc, operands, operand_count);
+		return TRUE;
+	}
+
+	packet_size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH;
+	avctp->cr = AVCTP_RESPONSE;
+
+	if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
+		avc->code = AVC_CTYPE_NOT_IMPLEMENTED;
+		goto done;
+	}
+
+	if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
+		avctp->ipid = 1;
+		packet_size = AVCTP_HEADER_LENGTH;
+		goto done;
+	}
+
+	handler = find_handler(control->handlers, avc->opcode);
+	if (!handler) {
+		DBG("handler not found for 0x%02x", avc->opcode);
+		avc->code = AVC_CTYPE_REJECTED;
+		goto done;
+	}
+
+	code = avc->code;
+	subunit = avc->subunit_type;
+
+	ret = handler->cb(session, avctp->transaction, &code,
+					&subunit, operands, operand_count,
+					handler->user_data);
+	if (ret < 0) {
+		if (ret == -EAGAIN)
+			return TRUE;
+		goto failed;
+	}
+
+	packet_size += ret;
+	avc->code = code;
+	avc->subunit_type = subunit;
+
+done:
+	ret = write(sock, buf, packet_size);
+	if (ret != packet_size)
+		goto failed;
+
+	return TRUE;
+
+failed:
+	DBG("AVCTP session %p got disconnected", session);
+	avctp_shutdown(session);
+	return FALSE;
+}
+
+static int uinput_create(const char *name)
+{
+	struct uinput_dev dev;
+	int fd, err, i;
+
+	fd = open("/dev/uinput", O_RDWR);
+	if (fd < 0) {
+		fd = open("/dev/input/uinput", O_RDWR);
+		if (fd < 0) {
+			fd = open("/dev/misc/uinput", O_RDWR);
+			if (fd < 0) {
+				err = -errno;
+				error("Can't open input device: %s (%d)",
+							strerror(-err), -err);
+				return err;
+			}
+		}
+	}
+
+	memset(&dev, 0, sizeof(dev));
+	if (name)
+		strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
+
+	dev.id.bustype = BUS_BLUETOOTH;
+	dev.id.vendor  = 0x0000;
+	dev.id.product = 0x0000;
+	dev.id.version = 0x0000;
+
+	if (write(fd, &dev, sizeof(dev)) < 0) {
+		err = -errno;
+		error("Can't write device information: %s (%d)",
+						strerror(-err), -err);
+		close(fd);
+		return err;
+	}
+
+	ioctl(fd, UI_SET_EVBIT, EV_KEY);
+	ioctl(fd, UI_SET_EVBIT, EV_REL);
+	ioctl(fd, UI_SET_EVBIT, EV_REP);
+	ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+	for (i = 0; key_map[i].name != NULL; i++)
+		ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
+
+	if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+		err = -errno;
+		error("Can't create uinput device: %s (%d)",
+						strerror(-err), -err);
+		close(fd);
+		return err;
+	}
+
+	return fd;
+}
+
+int avctp_init_uinput(struct avctp *session, const char *name,
+							const char *address)
+{
+	if (g_str_equal(name, "Nokia CK-20W")) {
+		session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE;
+		session->key_quirks[AVC_BACKWARD] |= QUIRK_NO_RELEASE;
+		session->key_quirks[AVC_PLAY] |= QUIRK_NO_RELEASE;
+		session->key_quirks[AVC_PAUSE] |= QUIRK_NO_RELEASE;
+	}
+
+	session->uinput = uinput_create(address);
+	if (session->uinput < 0) {
+		error("AVCTP: failed to init uinput for %s", address);
+		return session->uinput;
+	}
+
+	return 0;
+}
+
+static struct avctp_channel *avctp_channel_create(struct avctp *session, int fd,
+						size_t imtu, size_t omtu,
+						avctp_destroy_cb_t destroy)
+{
+	struct avctp_channel *chan;
+
+	chan = g_new0(struct avctp_channel, 1);
+	chan->session = session;
+	chan->io = g_io_channel_unix_new(fd);
+	chan->queue = g_queue_new();
+	chan->imtu = imtu;
+	chan->omtu = omtu;
+	chan->buffer = g_malloc0(MAX(imtu, omtu));
+	chan->destroy = destroy;
+
+	return chan;
+}
+
+static void handler_free(void *data)
+{
+	struct avctp_browsing_pdu_handler *handler = data;
+
+	if (handler->destroy)
+		handler->destroy(handler->user_data);
+
+	g_free(data);
+}
+
+static void avctp_destroy_browsing(void *data)
+{
+	struct avctp_channel *chan = data;
+
+	g_slist_free_full(chan->handlers, handler_free);
+
+	chan->handlers = NULL;
+}
+
+static struct avctp_pending_req *pending_create(struct avctp_channel *chan,
+						avctp_process_cb process,
+						void *data,
+						avctp_destroy_cb_t destroy)
+{
+	struct avctp_pending_req *p;
+	GSList *l, *tmp;
+
+	if (!chan->processed)
+		goto done;
+
+	tmp = g_slist_copy(chan->processed);
+
+	/* Find first unused transaction id */
+	for (l = tmp; l; l = g_slist_next(l)) {
+		struct avctp_pending_req *req = l->data;
+
+		if (req->transaction == chan->transaction) {
+			chan->transaction++;
+			chan->transaction %= 16;
+			tmp = g_slist_delete_link(tmp, l);
+			l = tmp;
+		}
+	}
+
+	g_slist_free(tmp);
+
+done:
+	p = g_new0(struct avctp_pending_req, 1);
+	p->chan = chan;
+	p->transaction = chan->transaction;
+	p->process = process;
+	p->data = data;
+	p->destroy = destroy;
+
+	chan->transaction++;
+	chan->transaction %= 16;
+
+	return p;
+}
+
+static int avctp_send_req(struct avctp *session, uint8_t code, uint8_t subunit,
+			uint8_t opcode, const struct iovec *iov, int iov_cnt,
+			avctp_rsp_cb func, void *user_data)
+{
+	struct avctp_channel *control = session->control;
+	struct avctp_pending_req *p;
+	struct avctp_control_req *req;
+	struct iovec *pdu;
+	int i;
+
+	if (control == NULL)
+		return -ENOTCONN;
+
+	pdu = g_new0(struct iovec, iov_cnt);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i].iov_len = iov[i].iov_len;
+		pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len);
+	}
+
+	req = g_new0(struct avctp_control_req, 1);
+	req->code = code;
+	req->subunit = subunit;
+	req->op = opcode;
+	req->func = func;
+	req->iov = pdu;
+	req->iov_cnt = iov_cnt;
+	req->user_data = user_data;
+
+	p = pending_create(control, process_control, req, control_req_destroy);
+
+	req->p = p;
+
+	g_queue_push_tail(control->queue, p);
+
+	if (control->process_id == 0)
+		control->process_id = g_idle_add(process_queue, control);
+
+	return 0;
+}
+
+int avctp_send_browsing_req(struct avctp *session,
+				const struct iovec *iov, int iov_cnt,
+				avctp_browsing_rsp_cb func, void *user_data)
+{
+	struct avctp_channel *browsing = session->browsing;
+	struct avctp_pending_req *p;
+	struct avctp_browsing_req *req;
+	struct iovec *pdu;
+	int i;
+
+	if (browsing == NULL)
+		return -ENOTCONN;
+
+	pdu = g_new0(struct iovec, iov_cnt);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i].iov_len = iov[i].iov_len;
+		pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len);
+	}
+
+	req = g_new0(struct avctp_browsing_req, 1);
+	req->func = func;
+	req->iov = pdu;
+	req->iov_cnt = iov_cnt;
+	req->user_data = user_data;
+
+	p = pending_create(browsing, process_browsing, req,
+			browsing_req_destroy);
+
+	req->p = p;
+
+	g_queue_push_tail(browsing->queue, p);
+
+	/* Connection did not complete, delay process of the request */
+	if (browsing->watch == 0)
+		return 0;
+
+	if (browsing->process_id == 0)
+		browsing->process_id = g_idle_add(process_queue, browsing);
+
+	return 0;
+}
+
+int avctp_send_browsing(struct avctp *session, uint8_t transaction,
+					const struct iovec *iov, int iov_cnt)
+{
+	struct avctp_channel *browsing = session->browsing;
+
+	if (browsing == NULL)
+		return -ENOTCONN;
+
+	return avctp_browsing_send(browsing, transaction, AVCTP_RESPONSE,
+								iov, iov_cnt);
+}
+
+static const char *op2str(uint8_t op)
+{
+	int i;
+
+	for (i = 0; key_map[i].name != NULL; i++) {
+		if ((op & 0x7F) == key_map[i].avc)
+			return key_map[i].name;
+	}
+
+	return "UNKNOWN";
+}
+
+static int avctp_passthrough_press(struct avctp *session, uint8_t op,
+					uint8_t *params, size_t params_len)
+{
+	struct iovec iov[2];
+	int iov_cnt;
+	uint8_t operands[2];
+
+	DBG("%s", op2str(op));
+
+	iov[0].iov_base = operands;
+	iov[0].iov_len = sizeof(operands);
+
+	/* Button pressed */
+	operands[0] = op & 0x7f;
+
+	if (params_len > 0) {
+		iov[1].iov_base = params;
+		iov[1].iov_len = params_len;
+		iov_cnt = 2;
+		operands[1] = params_len;
+	} else {
+		iov_cnt = 1;
+		operands[1] = 0;
+	}
+
+	return avctp_send_req(session, AVC_CTYPE_CONTROL,
+				AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+				iov, iov_cnt, avctp_passthrough_rsp, NULL);
+}
+
+static int avctp_passthrough_release(struct avctp *session, uint8_t op,
+					uint8_t *params, size_t params_len)
+{
+	struct iovec iov[2];
+	int iov_cnt;
+	uint8_t operands[2];
+
+	DBG("%s", op2str(op));
+
+	iov[0].iov_base = operands;
+	iov[0].iov_len = sizeof(operands);
+
+	/* Button released */
+	operands[0] = op | 0x80;
+
+	if (params_len > 0) {
+		iov[1].iov_base = params;
+		iov[1].iov_len = params_len;
+		iov_cnt = 2;
+		operands[1] = params_len;
+	} else {
+		iov_cnt = 1;
+		operands[1] = 0;
+	}
+
+	return avctp_send_req(session, AVC_CTYPE_CONTROL,
+				AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+				iov, iov_cnt, NULL, NULL);
+}
+
+static gboolean repeat_timeout(gpointer user_data)
+{
+	struct avctp *session = user_data;
+
+	avctp_passthrough_release(session, session->key.op, session->key.params,
+						session->key.params_len);
+	avctp_passthrough_press(session, session->key.op, session->key.params,
+						session->key.params_len);
+
+	return TRUE;
+}
+
+static void release_pressed(struct avctp *session)
+{
+	avctp_passthrough_release(session, session->key.op, session->key.params,
+						session->key.params_len);
+
+	if (session->key.timer > 0)
+		g_source_remove(session->key.timer);
+
+	session->key.timer = 0;
+}
+
+static bool set_pressed(struct avctp *session, uint8_t op, uint8_t *params,
+							size_t params_len)
+{
+	if (session->key.timer > 0) {
+		if (session->key.op == op)
+			return TRUE;
+		release_pressed(session);
+	}
+
+	if (op != AVC_FAST_FORWARD && op != AVC_REWIND)
+		return FALSE;
+
+	session->key.op = op;
+	session->key.params = params;
+	session->key.params_len = params_len;
+	session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
+							repeat_timeout,
+							session);
+
+	return TRUE;
+}
+
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+					uint8_t subunit, uint8_t *operands,
+					size_t operand_count, void *user_data)
+{
+	uint8_t *params;
+	size_t params_len;
+
+	DBG("code 0x%02x operand_count %zd", code, operand_count);
+
+	if (code != AVC_CTYPE_ACCEPTED)
+		return FALSE;
+
+	if (operands[0] == AVC_VENDOR_UNIQUE) {
+		params = &operands[2];
+		params_len = operand_count - 2;
+	} else {
+		params = NULL;
+		params_len = 0;
+	}
+
+	if (set_pressed(session, operands[0], params, params_len))
+		return FALSE;
+
+	avctp_passthrough_release(session, operands[0], params, params_len);
+
+	return FALSE;
+}
+
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+							size_t params_len)
+{
+	/* Auto release if key pressed */
+	if (session->key.timer > 0)
+		release_pressed(session);
+
+	return avctp_passthrough_press(session, op, params, params_len);
+}
+
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
+				uint8_t code, uint8_t subunit,
+				const struct iovec *iov, int iov_cnt)
+{
+	struct avctp_channel *control = session->control;
+
+	if (control == NULL)
+		return -ENOTCONN;
+
+	return avctp_send(control, transaction, AVCTP_RESPONSE, code, subunit,
+						AVC_OP_VENDORDEP, iov, iov_cnt);
+}
+
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+					const struct iovec *iov, int iov_cnt,
+					avctp_rsp_cb func, void *user_data)
+{
+	return avctp_send_req(session, code, subunit, AVC_OP_VENDORDEP, iov,
+						iov_cnt, func, user_data);
+}
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+						avctp_passthrough_cb cb,
+						void *user_data)
+{
+	struct avctp_channel *control = session->control;
+	struct avctp_passthrough_handler *handler;
+	static unsigned int id = 0;
+
+	if (control == NULL || session->handler != NULL)
+		return 0;
+
+	handler = g_new(struct avctp_passthrough_handler, 1);
+	handler->cb = cb;
+	handler->user_data = user_data;
+	handler->id = ++id;
+
+	session->handler = handler;
+
+	return handler->id;
+}
+
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+							unsigned int id)
+{
+	if (session->handler == NULL)
+		return false;
+
+	if (session->handler->id != id)
+		return false;
+
+	g_free(session->handler);
+	session->handler = NULL;
+	return true;
+}
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+						avctp_control_pdu_cb cb,
+						void *user_data)
+{
+	struct avctp_channel *control = session->control;
+	struct avctp_pdu_handler *handler;
+	static unsigned int id = 0;
+
+	if (control == NULL)
+		return 0;
+
+	handler = find_handler(control->handlers, opcode);
+	if (handler)
+		return 0;
+
+	handler = g_new(struct avctp_pdu_handler, 1);
+	handler->opcode = opcode;
+	handler->cb = cb;
+	handler->user_data = user_data;
+	handler->id = ++id;
+
+	control->handlers = g_slist_append(control->handlers, handler);
+
+	return handler->id;
+}
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+						avctp_browsing_pdu_cb cb,
+						void *user_data,
+						avctp_destroy_cb_t destroy)
+{
+	struct avctp_channel *browsing = session->browsing;
+	struct avctp_browsing_pdu_handler *handler;
+	static unsigned int id = 0;
+
+	if (browsing == NULL)
+		return 0;
+
+	if (browsing->handlers != NULL)
+		return 0;
+
+	handler = g_new(struct avctp_browsing_pdu_handler, 1);
+	handler->cb = cb;
+	handler->user_data = user_data;
+	handler->id = ++id;
+	handler->destroy = destroy;
+
+	browsing->handlers = g_slist_append(browsing->handlers, handler);
+
+	return handler->id;
+}
+
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id)
+{
+	struct avctp_channel *control = session->control;
+	GSList *l;
+
+	if (!control)
+		return false;
+
+	for (l = control->handlers; l; l = g_slist_next(l)) {
+		struct avctp_pdu_handler *handler = l->data;
+
+		if (handler->id != id)
+			continue;
+
+		control->handlers = g_slist_remove(control->handlers, handler);
+		g_free(handler);
+		return true;
+	}
+
+	return false;
+}
+
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+							unsigned int id)
+{
+	struct avctp_channel *browsing = session->browsing;
+	GSList *l;
+
+	if (browsing == NULL)
+		return false;
+
+	for (l = browsing->handlers; l; l = g_slist_next(l)) {
+		struct avctp_browsing_pdu_handler *handler = l->data;
+
+		if (handler->id != id)
+			continue;
+
+		browsing->handlers = g_slist_remove(browsing->handlers,
+								handler);
+		g_free(handler);
+		return true;
+	}
+
+	return false;
+}
+
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
+{
+	struct avctp *session;
+	struct avctp_channel *control;
+	GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+	session = g_new0(struct avctp, 1);
+	session->version = version;
+
+	control = avctp_channel_create(session, fd, imtu, omtu, NULL);
+	if (!control) {
+		g_free(session);
+		return NULL;
+	}
+
+	session->uinput = -1;
+	session->control = control;
+	session->passthrough_id = avctp_register_pdu_handler(session,
+						AVC_OP_PASSTHROUGH,
+						handle_panel_passthrough,
+						NULL);
+	session->unit_id = avctp_register_pdu_handler(session,
+						AVC_OP_UNITINFO,
+						handle_unit_info,
+						NULL);
+	session->subunit_id = avctp_register_pdu_handler(session,
+						AVC_OP_SUBUNITINFO,
+						handle_subunit_info,
+						NULL);
+
+	control->watch = g_io_add_watch(session->control->io, cond,
+						(GIOFunc) session_cb, session);
+
+	return avctp_ref(session);
+}
+
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+								size_t omtu)
+{
+	struct avctp_channel *browsing;
+	GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+	if (session->browsing)
+		return -EISCONN;
+
+	browsing = avctp_channel_create(session, fd, imtu, omtu,
+						avctp_destroy_browsing);
+	if (!browsing)
+		return -EINVAL;
+
+	session->browsing = browsing;
+	browsing->watch = g_io_add_watch(session->browsing->io, cond,
+					(GIOFunc) session_browsing_cb, session);
+
+	return 0;
+}
+
+void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb,
+							void *user_data)
+{
+	session->destroy = cb;
+	session->data = user_data;
+}
+
+void avctp_shutdown(struct avctp *session)
+{
+	if (!session)
+		return;
+
+	avctp_unref(session);
+}
diff --git a/repo/android/avctp.h b/repo/android/avctp.h
new file mode 100644
index 0000000..f0da2b3
--- /dev/null
+++ b/repo/android/avctp.h
@@ -0,0 +1,183 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#define AVCTP_CONTROL_PSM		23
+#define AVCTP_BROWSING_PSM		27
+
+#define AVCTP_HEADER_LENGTH		3
+#define AVC_HEADER_LENGTH		3
+
+#define AVC_DATA_OFFSET			AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH
+#define AVC_DATA_MTU			512
+
+/* ctype entries */
+#define AVC_CTYPE_CONTROL		0x0
+#define AVC_CTYPE_STATUS		0x1
+#define AVC_CTYPE_NOTIFY		0x3
+#define AVC_CTYPE_NOT_IMPLEMENTED	0x8
+#define AVC_CTYPE_ACCEPTED		0x9
+#define AVC_CTYPE_REJECTED		0xA
+#define AVC_CTYPE_STABLE		0xC
+#define AVC_CTYPE_CHANGED		0xD
+#define AVC_CTYPE_INTERIM		0xF
+
+/* opcodes */
+#define AVC_OP_VENDORDEP		0x00
+#define AVC_OP_UNITINFO			0x30
+#define AVC_OP_SUBUNITINFO		0x31
+#define AVC_OP_PASSTHROUGH		0x7c
+
+/* subunits of interest */
+#define AVC_SUBUNIT_PANEL		0x09
+
+/* operands in passthrough commands */
+#define AVC_SELECT			0x00
+#define AVC_UP				0x01
+#define AVC_DOWN			0x02
+#define AVC_LEFT			0x03
+#define AVC_RIGHT			0x04
+#define AVC_ROOT_MENU			0x09
+#define AVC_CONTENTS_MENU		0x0b
+#define AVC_FAVORITE_MENU		0x0c
+#define AVC_EXIT			0x0d
+#define AVC_ON_DEMAND_MENU		0x0e
+#define AVC_APPS_MENU			0x0f
+#define AVC_0				0x20
+#define AVC_1				0x21
+#define AVC_2				0x22
+#define AVC_3				0x23
+#define AVC_4				0x24
+#define AVC_5				0x25
+#define AVC_6				0x26
+#define AVC_7				0x27
+#define AVC_8				0x28
+#define AVC_9				0x29
+#define AVC_DOT				0x2a
+#define AVC_ENTER			0x2b
+#define AVC_CHANNEL_UP			0x30
+#define AVC_CHANNEL_DOWN		0x31
+#define AVC_CHANNEL_PREVIOUS		0x32
+#define AVC_INPUT_SELECT		0x34
+#define AVC_INFO			0x35
+#define AVC_HELP			0x36
+#define AVC_PAGE_UP			0x37
+#define AVC_PAGE_DOWN			0x38
+#define AVC_LOCK			0x3a
+#define AVC_POWER			0x40
+#define AVC_VOLUME_UP			0x41
+#define AVC_VOLUME_DOWN			0x42
+#define AVC_MUTE			0x43
+#define AVC_PLAY			0x44
+#define AVC_STOP			0x45
+#define AVC_PAUSE			0x46
+#define AVC_RECORD			0x47
+#define AVC_REWIND			0x48
+#define AVC_FAST_FORWARD		0x49
+#define AVC_EJECT			0x4a
+#define AVC_FORWARD			0x4b
+#define AVC_BACKWARD			0x4c
+#define AVC_LIST			0x4d
+#define AVC_F1				0x71
+#define AVC_F2				0x72
+#define AVC_F3				0x73
+#define AVC_F4				0x74
+#define AVC_F5				0x75
+#define AVC_F6				0x76
+#define AVC_F7				0x77
+#define AVC_F8				0x78
+#define AVC_F9				0x79
+#define AVC_RED				0x7a
+#define AVC_GREEN			0x7b
+#define AVC_BLUE			0x7c
+#define AVC_YELLOW			0x7c
+
+#define AVC_VENDOR_UNIQUE		0x7e
+
+#define AVC_VENDOR_NEXT_GROUP		0x00
+#define AVC_VENDOR_PREV_GROUP		0x01
+
+struct avctp;
+
+typedef bool (*avctp_passthrough_cb) (struct avctp *session,
+					uint8_t op, bool pressed,
+					void *user_data);
+typedef ssize_t (*avctp_control_pdu_cb) (struct avctp *session,
+					uint8_t transaction, uint8_t *code,
+					uint8_t *subunit, uint8_t *operands,
+					size_t operand_count, void *user_data);
+typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
+					uint8_t subunit, uint8_t *operands,
+					size_t operand_count, void *user_data);
+typedef gboolean (*avctp_browsing_rsp_cb) (struct avctp *session,
+					uint8_t *operands, size_t operand_count,
+					void *user_data);
+typedef ssize_t (*avctp_browsing_pdu_cb) (struct avctp *session,
+					uint8_t transaction,
+					uint8_t *operands, size_t operand_count,
+					void *user_data);
+
+typedef void (*avctp_destroy_cb_t) (void *user_data);
+
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb,
+							void *user_data);
+
+int avctp_init_uinput(struct avctp *session, const char *name,
+							const char *address);
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+								size_t omtu);
+
+void avctp_shutdown(struct avctp *session);
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+						avctp_passthrough_cb cb,
+						void *user_data);
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+							unsigned int id);
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+						avctp_control_pdu_cb cb,
+						void *user_data);
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id);
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+						avctp_browsing_pdu_cb cb,
+						void *user_data,
+						avctp_destroy_cb_t destroy);
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+							unsigned int id);
+
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+							size_t params_len);
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
+				uint8_t code, uint8_t subunit,
+				const struct iovec *iov, int iov_cnt);
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+					const struct iovec *iov, int iov_cnt,
+					avctp_rsp_cb func, void *user_data);
+int avctp_send_browsing(struct avctp *session, uint8_t transaction,
+					const struct iovec *iov, int iov_cnt);
+int avctp_send_browsing_req(struct avctp *session,
+				const struct iovec *iov, int iov_cnt,
+				avctp_browsing_rsp_cb func, void *user_data);
diff --git a/repo/android/avdtp.c b/repo/android/avdtp.c
new file mode 100644
index 0000000..bab305b
--- /dev/null
+++ b/repo/android/avdtp.c
@@ -0,0 +1,3484 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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 <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "avdtp.h"
+#include "../profiles/audio/a2dp-codecs.h"
+
+#define MAX_SEID 0x3E
+static unsigned int seids;
+
+#ifndef MAX
+# define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define AVDTP_DISCOVER				0x01
+#define AVDTP_GET_CAPABILITIES			0x02
+#define AVDTP_SET_CONFIGURATION			0x03
+#define AVDTP_GET_CONFIGURATION			0x04
+#define AVDTP_RECONFIGURE			0x05
+#define AVDTP_OPEN				0x06
+#define AVDTP_START				0x07
+#define AVDTP_CLOSE				0x08
+#define AVDTP_SUSPEND				0x09
+#define AVDTP_ABORT				0x0A
+#define AVDTP_SECURITY_CONTROL			0x0B
+#define AVDTP_GET_ALL_CAPABILITIES		0x0C
+#define AVDTP_DELAY_REPORT			0x0D
+
+#define AVDTP_PKT_TYPE_SINGLE			0x00
+#define AVDTP_PKT_TYPE_START			0x01
+#define AVDTP_PKT_TYPE_CONTINUE			0x02
+#define AVDTP_PKT_TYPE_END			0x03
+
+#define AVDTP_MSG_TYPE_COMMAND			0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT		0x01
+#define AVDTP_MSG_TYPE_ACCEPT			0x02
+#define AVDTP_MSG_TYPE_REJECT			0x03
+
+#define REQ_TIMEOUT 6
+#define ABORT_TIMEOUT 2
+#define DISCONNECT_TIMEOUT 1
+#define START_TIMEOUT 1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_common_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+} __attribute__ ((packed));
+
+struct avdtp_single_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint8_t signal_id:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint8_t no_of_packets;
+	uint8_t signal_id:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+} __attribute__ ((packed));
+
+struct seid_info {
+	uint8_t rfa0:1;
+	uint8_t inuse:1;
+	uint8_t seid:6;
+	uint8_t rfa2:3;
+	uint8_t type:1;
+	uint8_t media_type:4;
+} __attribute__ ((packed));
+
+struct seid {
+	uint8_t rfa0:2;
+	uint8_t seid:6;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_common_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+} __attribute__ ((packed));
+
+struct avdtp_single_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+	uint8_t rfa0:2;
+	uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+	uint8_t no_of_packets;
+	uint8_t rfa0:2;
+	uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+} __attribute__ ((packed));
+
+struct seid_info {
+	uint8_t seid:6;
+	uint8_t inuse:1;
+	uint8_t rfa0:1;
+	uint8_t media_type:4;
+	uint8_t type:1;
+	uint8_t rfa2:3;
+} __attribute__ ((packed));
+
+struct seid {
+	uint8_t seid:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* packets */
+
+struct discover_resp {
+	struct seid_info seps[0];
+} __attribute__ ((packed));
+
+struct getcap_resp {
+	uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct start_req {
+	struct seid first_seid;
+	struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct suspend_req {
+	struct seid first_seid;
+	struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct seid_rej {
+	uint8_t error;
+} __attribute__ ((packed));
+
+struct conf_rej {
+	uint8_t category;
+	uint8_t error;
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct seid_req {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+} __attribute__ ((packed));
+
+struct setconf_req {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+	uint8_t rfa1:2;
+	uint8_t int_seid:6;
+
+	uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+	uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+
+	uint8_t serv_cap;
+	uint8_t serv_cap_len;
+
+	uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct delay_req {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+	uint16_t delay;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct seid_req {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct setconf_req {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+	uint8_t int_seid:6;
+	uint8_t rfa1:2;
+
+	uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+	uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+
+	uint8_t serv_cap;
+	uint8_t serv_cap_len;
+
+	uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct delay_req {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+	uint16_t delay;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct in_buf {
+	gboolean active;
+	int no_of_packets;
+	uint8_t transaction;
+	uint8_t message_type;
+	uint8_t signal_id;
+	uint8_t buf[1024];
+	uint8_t data_size;
+};
+
+struct pending_req {
+	uint8_t transaction;
+	uint8_t signal_id;
+	void *data;
+	size_t data_size;
+	struct avdtp_stream *stream; /* Set if the request targeted a stream */
+	guint timeout;
+	gboolean collided;
+};
+
+struct avdtp_remote_sep {
+	uint8_t seid;
+	uint8_t type;
+	uint8_t media_type;
+	struct avdtp_service_capability *codec;
+	gboolean delay_reporting;
+	GSList *caps; /* of type struct avdtp_service_capability */
+	struct avdtp_stream *stream;
+};
+
+struct avdtp_local_sep {
+	avdtp_state_t state;
+	struct avdtp_stream *stream;
+	struct seid_info info;
+	uint8_t codec;
+	uint32_t vndcodec_vendor;
+	uint16_t vndcodec_codec;
+	gboolean delay_reporting;
+	GSList *caps;
+	struct avdtp_sep_ind *ind;
+	struct avdtp_sep_cfm *cfm;
+	void *user_data;
+};
+
+struct stream_callback {
+	avdtp_stream_state_cb cb;
+	void *user_data;
+	unsigned int id;
+};
+
+struct discover_callback {
+	unsigned int id;
+	avdtp_discover_cb_t cb;
+	void *user_data;
+};
+
+struct disconnect_callback {
+	unsigned int id;
+	avdtp_disconnect_cb_t cb;
+	void *user_data;
+};
+
+struct avdtp_stream {
+	GIOChannel *io;
+	uint16_t imtu;
+	uint16_t omtu;
+	struct avdtp *session;
+	struct avdtp_local_sep *lsep;
+	uint8_t rseid;
+	GSList *caps;
+	GSList *callbacks;
+	struct avdtp_service_capability *codec;
+	guint io_id;		/* Transport GSource ID */
+	guint timer;		/* Waiting for other side to close or open
+				 * the transport channel */
+	gboolean open_acp;	/* If we are in ACT role for Open */
+	gboolean close_int;	/* If we are in INT role for Close */
+	gboolean abort_int;	/* If we are in INT role for Abort */
+	guint start_timer;	/* Wait START command timer */
+	gboolean delay_reporting;
+	uint16_t delay;		/* AVDTP 1.3 Delay Reporting feature */
+	gboolean starting;	/* only valid while sep state == OPEN */
+};
+
+/* Structure describing an AVDTP connection between two devices */
+
+struct avdtp {
+	unsigned int ref;
+
+	uint16_t version;
+
+	guint auth_id;
+
+	GIOChannel *io;
+	guint io_id;
+
+	GSList *seps; /* Elements of type struct avdtp_remote_sep * */
+	struct queue *lseps; /* Elements of type struct avdtp_local_sep * */
+
+	GSList *streams; /* Elements of type struct avdtp_stream * */
+
+	GSList *req_queue; /* Elements of type struct pending_req * */
+	GSList *prio_queue; /* Same as req_queue but is processed before it */
+
+	struct avdtp_stream *pending_open;
+
+	uint16_t imtu;
+	uint16_t omtu;
+
+	struct in_buf in;
+
+	char *buf;
+
+	struct discover_callback *discover;
+	struct pending_req *req;
+
+	GSList *disconnect;
+
+	bool shutdown;
+};
+
+static int send_request(struct avdtp *session, gboolean priority,
+			struct avdtp_stream *stream, uint8_t signal_id,
+			void *buffer, size_t size);
+static gboolean avdtp_parse_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					uint8_t transaction, uint8_t signal_id,
+					void *buf, int size);
+static gboolean avdtp_parse_rej(struct avdtp *session,
+					struct avdtp_stream *stream,
+					uint8_t transaction, uint8_t signal_id,
+					void *buf, int size);
+static int process_queue(struct avdtp *session);
+static void avdtp_sep_set_state(struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				avdtp_state_t state);
+
+static const char *avdtp_statestr(avdtp_state_t state)
+{
+	switch (state) {
+	case AVDTP_STATE_IDLE:
+		return "IDLE";
+	case AVDTP_STATE_CONFIGURED:
+		return "CONFIGURED";
+	case AVDTP_STATE_OPEN:
+		return "OPEN";
+	case AVDTP_STATE_STREAMING:
+		return "STREAMING";
+	case AVDTP_STATE_CLOSING:
+		return "CLOSING";
+	case AVDTP_STATE_ABORTING:
+		return "ABORTING";
+	default:
+		return "<unknown state>";
+	}
+}
+
+static gboolean try_send(int sk, void *data, size_t len)
+{
+	int err;
+
+	do {
+		err = send(sk, data, len, 0);
+	} while (err < 0 && errno == EINTR);
+
+	if (err < 0) {
+		error("send: %s (%d)", strerror(errno), errno);
+		return FALSE;
+	} else if ((size_t) err != len) {
+		error("try_send: complete buffer not sent (%d/%zu bytes)",
+								err, len);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
+				uint8_t message_type, uint8_t signal_id,
+				void *data, size_t len)
+{
+	unsigned int cont_fragments, sent;
+	struct avdtp_start_header start;
+	struct avdtp_continue_header cont;
+	int sock;
+
+	if (session->io == NULL) {
+		error("avdtp_send: session is closed");
+		return FALSE;
+	}
+
+	sock = g_io_channel_unix_get_fd(session->io);
+
+	/* Single packet - no fragmentation */
+	if (sizeof(struct avdtp_single_header) + len <= session->omtu) {
+		struct avdtp_single_header single;
+
+		memset(&single, 0, sizeof(single));
+
+		single.transaction = transaction;
+		single.packet_type = AVDTP_PKT_TYPE_SINGLE;
+		single.message_type = message_type;
+		single.signal_id = signal_id;
+
+		memcpy(session->buf, &single, sizeof(single));
+		memcpy(session->buf + sizeof(single), data, len);
+
+		return try_send(sock, session->buf, sizeof(single) + len);
+	}
+
+	/* Check if there is enough space to start packet */
+	if (session->omtu < sizeof(start)) {
+		error("No enough space to fragment packet");
+		return FALSE;
+	}
+
+	/* Count the number of needed fragments */
+	cont_fragments = (len - (session->omtu - sizeof(start))) /
+					(session->omtu - sizeof(cont)) + 1;
+
+	DBG("%zu bytes split into %d fragments", len, cont_fragments + 1);
+
+	/* Send the start packet */
+	memset(&start, 0, sizeof(start));
+	start.transaction = transaction;
+	start.packet_type = AVDTP_PKT_TYPE_START;
+	start.message_type = message_type;
+	start.no_of_packets = cont_fragments + 1;
+	start.signal_id = signal_id;
+
+	memcpy(session->buf, &start, sizeof(start));
+	memcpy(session->buf + sizeof(start), data,
+					session->omtu - sizeof(start));
+
+	if (!try_send(sock, session->buf, session->omtu))
+		return FALSE;
+
+	DBG("first packet with %zu bytes sent", session->omtu - sizeof(start));
+
+	sent = session->omtu - sizeof(start);
+
+	/* Send the continue fragments and the end packet */
+	while (sent < len) {
+		int left, to_copy;
+
+		left = len - sent;
+		if (left + sizeof(cont) > session->omtu) {
+			cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
+			to_copy = session->omtu - sizeof(cont);
+			DBG("sending continue with %d bytes", to_copy);
+		} else {
+			cont.packet_type = AVDTP_PKT_TYPE_END;
+			to_copy = left;
+			DBG("sending end with %d bytes", to_copy);
+		}
+
+		cont.transaction = transaction;
+		cont.message_type = message_type;
+
+		memcpy(session->buf, &cont, sizeof(cont));
+		memcpy(session->buf + sizeof(cont), data + sent, to_copy);
+
+		if (!try_send(sock, session->buf, to_copy + sizeof(cont)))
+			return FALSE;
+
+		sent += to_copy;
+	}
+
+	return TRUE;
+}
+
+static void pending_req_free(void *data)
+{
+	struct pending_req *req = data;
+
+	if (req->timeout)
+		g_source_remove(req->timeout);
+	g_free(req->data);
+	g_free(req);
+}
+
+static void close_stream(struct avdtp_stream *stream)
+{
+	int sock;
+
+	if (stream->io == NULL)
+		return;
+
+	sock = g_io_channel_unix_get_fd(stream->io);
+
+	shutdown(sock, SHUT_RDWR);
+
+	g_io_channel_shutdown(stream->io, FALSE, NULL);
+
+	g_io_channel_unref(stream->io);
+	stream->io = NULL;
+}
+
+static gboolean stream_close_timeout(gpointer user_data)
+{
+	struct avdtp_stream *stream = user_data;
+
+	DBG("Timed out waiting for peer to close the transport channel");
+
+	stream->timer = 0;
+
+	close_stream(stream);
+
+	return FALSE;
+}
+
+static gboolean stream_open_timeout(gpointer user_data)
+{
+	struct avdtp_stream *stream = user_data;
+
+	DBG("Timed out waiting for peer to open the transport channel");
+
+	stream->timer = 0;
+
+	stream->session->pending_open = NULL;
+
+	avdtp_abort(stream->session, stream);
+
+	return FALSE;
+}
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t category, int id)
+{
+	err->category = category;
+
+	if (category == AVDTP_ERRNO)
+		err->err.posix_errno = id;
+	else
+		err->err.error_code = id;
+}
+
+uint8_t avdtp_error_category(struct avdtp_error *err)
+{
+	return err->category;
+}
+
+int avdtp_error_error_code(struct avdtp_error *err)
+{
+	assert(err->category != AVDTP_ERRNO);
+	return err->err.error_code;
+}
+
+int avdtp_error_posix_errno(struct avdtp_error *err)
+{
+	assert(err->category == AVDTP_ERRNO);
+	return err->err.posix_errno;
+}
+
+static struct avdtp_stream *find_stream_by_rseid(struct avdtp *session,
+							uint8_t rseid)
+{
+	GSList *l;
+
+	for (l = session->streams; l != NULL; l = g_slist_next(l)) {
+		struct avdtp_stream *stream = l->data;
+
+		if (stream->rseid == rseid)
+			return stream;
+	}
+
+	return NULL;
+}
+
+static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid)
+{
+	GSList *l;
+
+	for (l = seps; l != NULL; l = g_slist_next(l)) {
+		struct avdtp_remote_sep *sep = l->data;
+
+		if (sep->seid == seid)
+			return sep;
+	}
+
+	return NULL;
+}
+
+static void stream_free(void *data)
+{
+	struct avdtp_stream *stream = data;
+	struct avdtp_remote_sep *rsep;
+
+	stream->lsep->info.inuse = 0;
+	stream->lsep->stream = NULL;
+
+	rsep = find_remote_sep(stream->session->seps, stream->rseid);
+	if (rsep)
+		rsep->stream = NULL;
+
+	if (stream->timer)
+		g_source_remove(stream->timer);
+
+	if (stream->start_timer > 0)
+		g_source_remove(stream->start_timer);
+
+	if (stream->io)
+		close_stream(stream);
+
+	if (stream->io_id)
+		g_source_remove(stream->io_id);
+
+	g_slist_free_full(stream->callbacks, g_free);
+	g_slist_free_full(stream->caps, g_free);
+
+	g_free(stream);
+}
+
+static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	struct avdtp_stream *stream = data;
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	if (stream->close_int && sep->cfm && sep->cfm->close)
+		sep->cfm->close(stream->session, sep, stream, NULL,
+				sep->user_data);
+
+	if (!(cond & G_IO_NVAL))
+		close_stream(stream);
+
+	stream->io_id = 0;
+
+	if (!stream->abort_int)
+		avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE);
+
+	return FALSE;
+}
+
+static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
+					uint16_t imtu, uint16_t omtu)
+{
+	struct avdtp_stream *stream = session->pending_open;
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	session->pending_open = NULL;
+
+	if (stream->timer) {
+		g_source_remove(stream->timer);
+		stream->timer = 0;
+	}
+
+	if (io == NULL)
+		return;
+
+	if (stream->io == NULL)
+		stream->io = g_io_channel_ref(io);
+
+	stream->omtu = omtu;
+	stream->imtu = imtu;
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+	stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+					(GIOFunc) transport_cb, stream);
+}
+
+static int pending_req_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct pending_req *req = a;
+	const struct avdtp_stream *stream = b;
+
+	if (req->stream == stream)
+		return 0;
+
+	return -1;
+}
+
+static void cleanup_queue(struct avdtp *session, struct avdtp_stream *stream)
+{
+	GSList *l;
+	struct pending_req *req;
+
+	while ((l = g_slist_find_custom(session->prio_queue, stream,
+							pending_req_cmp))) {
+		req = l->data;
+		pending_req_free(req);
+		session->prio_queue = g_slist_remove(session->prio_queue, req);
+	}
+
+	while ((l = g_slist_find_custom(session->req_queue, stream,
+							pending_req_cmp))) {
+		req = l->data;
+		pending_req_free(req);
+		session->req_queue = g_slist_remove(session->req_queue, req);
+	}
+}
+
+static void handle_unanswered_req(struct avdtp *session,
+						struct avdtp_stream *stream)
+{
+	struct pending_req *req;
+	struct avdtp_local_sep *lsep;
+	struct avdtp_error err;
+
+	if (!session->req->timeout)
+		/* Request is in process */
+		return;
+
+	if (session->req->signal_id == AVDTP_ABORT) {
+		/* Avoid freeing the Abort request here */
+		DBG("handle_unanswered_req: Abort req, returning");
+		session->req->stream = NULL;
+		return;
+	}
+
+	req = session->req;
+	session->req = NULL;
+
+	avdtp_error_init(&err, AVDTP_ERRNO, EIO);
+
+	lsep = stream->lsep;
+
+	switch (req->signal_id) {
+	case AVDTP_RECONFIGURE:
+		error("No reply to Reconfigure request");
+		if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+			lsep->cfm->reconfigure(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_OPEN:
+		error("No reply to Open request");
+		if (lsep && lsep->cfm && lsep->cfm->open)
+			lsep->cfm->open(session, lsep, stream, &err,
+					lsep->user_data);
+		break;
+	case AVDTP_START:
+		error("No reply to Start request");
+		if (lsep && lsep->cfm && lsep->cfm->start)
+			lsep->cfm->start(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_SUSPEND:
+		error("No reply to Suspend request");
+		if (lsep && lsep->cfm && lsep->cfm->suspend)
+			lsep->cfm->suspend(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_CLOSE:
+		error("No reply to Close request");
+		if (lsep && lsep->cfm && lsep->cfm->close)
+			lsep->cfm->close(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_SET_CONFIGURATION:
+		error("No reply to SetConfiguration request");
+		if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+			lsep->cfm->set_configuration(session, lsep, stream,
+							&err, lsep->user_data);
+	}
+
+	pending_req_free(req);
+}
+
+static void avdtp_sep_set_state(struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				avdtp_state_t state)
+{
+	struct avdtp_stream *stream = sep->stream;
+	avdtp_state_t old_state;
+	struct avdtp_error err, *err_ptr = NULL;
+	GSList *l;
+
+	if (!stream) {
+		error("Error changing sep state: stream not available");
+		return;
+	}
+
+	if (sep->state == state) {
+		avdtp_error_init(&err, AVDTP_ERRNO, EIO);
+		DBG("stream state change failed: %s", avdtp_strerror(&err));
+		err_ptr = &err;
+	} else {
+		err_ptr = NULL;
+		DBG("stream state changed: %s -> %s",
+				avdtp_statestr(sep->state),
+				avdtp_statestr(state));
+	}
+
+	old_state = sep->state;
+	sep->state = state;
+
+	switch (state) {
+	case AVDTP_STATE_CONFIGURED:
+		if (sep->info.type == AVDTP_SEP_TYPE_SINK)
+			avdtp_delay_report(session, stream, stream->delay);
+		break;
+	case AVDTP_STATE_OPEN:
+		stream->starting = FALSE;
+		break;
+	case AVDTP_STATE_STREAMING:
+		if (stream->start_timer) {
+			g_source_remove(stream->start_timer);
+			stream->start_timer = 0;
+		}
+		stream->open_acp = FALSE;
+		break;
+	case AVDTP_STATE_CLOSING:
+	case AVDTP_STATE_ABORTING:
+		if (stream->start_timer) {
+			g_source_remove(stream->start_timer);
+			stream->start_timer = 0;
+		}
+		break;
+	case AVDTP_STATE_IDLE:
+		if (stream->start_timer) {
+			g_source_remove(stream->start_timer);
+			stream->start_timer = 0;
+		}
+		if (session->pending_open == stream)
+			handle_transport_connect(session, NULL, 0, 0);
+		if (session->req && session->req->stream == stream)
+			handle_unanswered_req(session, stream);
+		/* Remove pending commands for this stream from the queue */
+		cleanup_queue(session, stream);
+		break;
+	default:
+		break;
+	}
+
+	l = stream->callbacks;
+	while (l != NULL) {
+		struct stream_callback *cb = l->data;
+		l = g_slist_next(l);
+		cb->cb(stream, old_state, state, err_ptr, cb->user_data);
+	}
+
+	if (state == AVDTP_STATE_IDLE &&
+				g_slist_find(session->streams, stream)) {
+		session->streams = g_slist_remove(session->streams, stream);
+		stream_free(stream);
+	}
+
+	if (session->io && session->shutdown && session->streams == NULL) {
+		int sock = g_io_channel_unix_get_fd(session->io);
+		shutdown(sock, SHUT_RDWR);
+	}
+}
+
+static void finalize_discovery(struct avdtp *session, int err)
+{
+	struct discover_callback *discover = session->discover;
+	struct avdtp_error avdtp_err;
+
+	if (!discover)
+		return;
+
+	session->discover = NULL;
+
+	avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
+
+	if (discover->id > 0)
+		g_source_remove(discover->id);
+
+	if (discover->cb)
+		discover->cb(session, session->seps, err ? &avdtp_err : NULL,
+							discover->user_data);
+	g_free(discover);
+}
+
+static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	if (sep->cfm && sep->cfm->abort &&
+				(sep->state != AVDTP_STATE_ABORTING ||
+							stream->abort_int))
+		sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+}
+
+static void sep_free(gpointer data)
+{
+	struct avdtp_remote_sep *sep = data;
+
+	g_slist_free_full(sep->caps, g_free);
+	g_free(sep);
+}
+
+static void avdtp_free(void *data)
+{
+	struct avdtp *session = data;
+
+	DBG("%p", session);
+
+	g_slist_free_full(session->streams, stream_free);
+
+	if (session->io) {
+		g_io_channel_shutdown(session->io, FALSE, NULL);
+		g_io_channel_unref(session->io);
+	}
+
+	if (session->io_id) {
+		g_source_remove(session->io_id);
+		session->io_id = 0;
+	}
+
+	if (session->req)
+		pending_req_free(session->req);
+
+	g_slist_free_full(session->req_queue, pending_req_free);
+	g_slist_free_full(session->prio_queue, pending_req_free);
+	g_slist_free_full(session->seps, sep_free);
+	g_slist_free_full(session->disconnect, g_free);
+
+	/* Free copy of the SEP list */
+	session->lseps = NULL;
+
+	g_free(session->buf);
+
+	g_free(session);
+}
+
+static void process_disconnect(void *data)
+{
+	struct disconnect_callback *callback = data;
+
+	callback->cb(callback->user_data);
+
+	g_free(callback);
+}
+
+static void connection_lost(struct avdtp *session, int err)
+{
+	DBG("Disconnected: %s (%d)", strerror(err), err);
+
+	g_slist_foreach(session->streams, (GFunc) release_stream, session);
+	session->streams = NULL;
+
+	avdtp_ref(session);
+
+	finalize_discovery(session, err);
+
+	g_slist_free_full(session->disconnect, process_disconnect);
+	session->disconnect = NULL;
+
+	avdtp_unref(session);
+}
+
+void avdtp_unref(struct avdtp *session)
+{
+	if (!session)
+		return;
+
+	session->ref--;
+
+	DBG("%p: ref=%d", session, session->ref);
+
+	if (session->ref > 0)
+		return;
+
+	finalize_discovery(session, ECONNABORTED);
+
+	avdtp_free(session);
+}
+
+struct avdtp *avdtp_ref(struct avdtp *session)
+{
+	session->ref++;
+
+	DBG("%p: ref=%d", session, session->ref);
+
+	return session;
+}
+
+static bool match_by_seid(const void *data, const void *user_data)
+{
+	const struct avdtp_local_sep *sep = data;
+	uint8_t seid = PTR_TO_UINT(user_data);
+
+	return sep->info.seid == seid;
+}
+
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp *session,
+								uint8_t seid)
+{
+	return queue_find(session->lseps, match_by_seid, INT_TO_PTR(seid));
+}
+
+struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
+						struct avdtp_local_sep *lsep)
+{
+	GSList *l;
+
+	if (lsep->info.inuse)
+		return NULL;
+
+	for (l = session->seps; l != NULL; l = g_slist_next(l)) {
+		struct avdtp_remote_sep *sep = l->data;
+		struct avdtp_service_capability *cap;
+		struct avdtp_media_codec_capability *codec_data;
+
+		/* Type must be different: source <-> sink */
+		if (sep->type == lsep->info.type)
+			continue;
+
+		if (sep->media_type != lsep->info.media_type)
+			continue;
+
+		if (!sep->codec)
+			continue;
+
+		cap = sep->codec;
+		codec_data = (void *) cap->data;
+
+		if (codec_data->media_codec_type != lsep->codec)
+			continue;
+
+		/* FIXME: Add Vendor Specific Codec match to SEP callback */
+		if (lsep->codec == A2DP_CODEC_VENDOR) {
+			a2dp_vendor_codec_t *vndcodec =
+						(void *) codec_data->data;
+
+			if (btohl(vndcodec->vendor_id) != lsep->vndcodec_vendor)
+				continue;
+
+			if (btohs(vndcodec->codec_id) != lsep->vndcodec_codec)
+				continue;
+		}
+
+		if (sep->stream == NULL)
+			return sep;
+	}
+
+	return NULL;
+}
+
+static GSList *caps_to_list(uint8_t *data, int size,
+				struct avdtp_service_capability **codec,
+				gboolean *delay_reporting)
+{
+	GSList *caps;
+	int processed;
+
+	if (delay_reporting)
+		*delay_reporting = FALSE;
+
+	for (processed = 0, caps = NULL; processed + 2 <= size;) {
+		struct avdtp_service_capability *cap;
+		uint8_t length, category;
+
+		category = data[0];
+		length = data[1];
+
+		if (processed + 2 + length > size) {
+			error("Invalid capability data in getcap resp");
+			break;
+		}
+
+		cap = g_malloc(sizeof(struct avdtp_service_capability) +
+					length);
+		memcpy(cap, data, 2 + length);
+
+		processed += 2 + length;
+		data += 2 + length;
+
+		caps = g_slist_append(caps, cap);
+
+		if (category == AVDTP_MEDIA_CODEC &&
+				length >=
+				sizeof(struct avdtp_media_codec_capability))
+			*codec = cap;
+		else if (category == AVDTP_DELAY_REPORTING && delay_reporting)
+			*delay_reporting = TRUE;
+	}
+
+	return caps;
+}
+
+static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
+							uint8_t signal_id)
+{
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_GEN_REJECT,
+							signal_id, NULL, 0);
+}
+
+static void copy_seps(void *data, void *user_data)
+{
+	struct avdtp_local_sep *sep = data;
+	struct seid_info **p = user_data;
+
+	memcpy(*p, &sep->info, sizeof(struct seid_info));
+	*p = *p + 1;
+}
+
+static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
+							void *buf, int size)
+{
+	unsigned int rsp_size, sep_count;
+	struct seid_info *seps, *p;
+	gboolean ret;
+
+	sep_count = queue_length(session->lseps);
+
+	if (sep_count == 0) {
+		uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
+		return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+					AVDTP_DISCOVER, &err, sizeof(err));
+	}
+
+	rsp_size = sep_count * sizeof(struct seid_info);
+
+	seps = g_new0(struct seid_info, sep_count);
+	p = seps;
+
+	queue_foreach(session->lseps, copy_seps, &p);
+
+	ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+				AVDTP_DISCOVER, seps, rsp_size);
+	g_free(seps);
+
+	return ret;
+}
+
+static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
+					struct seid_req *req, unsigned int size,
+					gboolean get_all)
+{
+	GSList *l, *caps;
+	struct avdtp_local_sep *sep = NULL;
+	unsigned int rsp_size;
+	uint8_t err, buf[1024], *ptr = buf;
+	uint8_t cmd;
+
+	cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES;
+
+	if (size < sizeof(struct seid_req)) {
+		err = AVDTP_BAD_LENGTH;
+		goto failed;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	if (!sep->ind->get_capability(session, sep, &caps, &err,
+							sep->user_data))
+		goto failed;
+
+	for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) {
+		struct avdtp_service_capability *cap = l->data;
+
+		if (rsp_size + cap->length + 2 > sizeof(buf))
+			break;
+
+		memcpy(ptr, cap, cap->length + 2);
+		rsp_size += cap->length + 2;
+		ptr += cap->length + 2;
+
+		g_free(cap);
+	}
+
+	if (get_all && sep->delay_reporting) {
+		ptr[0] = AVDTP_DELAY_REPORTING;
+		ptr[1] = 0x00;
+		rsp_size += 2;
+	}
+
+	g_slist_free(caps);
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd,
+								buf, rsp_size);
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd,
+							&err, sizeof(err));
+}
+
+static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream,
+						struct avdtp_error *err)
+{
+	struct conf_rej rej;
+	struct avdtp_local_sep *sep;
+
+	if (err != NULL) {
+		rej.error = AVDTP_UNSUPPORTED_CONFIGURATION;
+		rej.category = err->err.error_code;
+		avdtp_send(session, session->in.transaction,
+				AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION,
+				&rej, sizeof(rej));
+		return;
+	}
+
+	if (!avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_ACCEPT,
+					AVDTP_SET_CONFIGURATION, NULL, 0)) {
+		stream_free(stream);
+		return;
+	}
+
+	sep = stream->lsep;
+	sep->stream = stream;
+	sep->info.inuse = 1;
+	session->streams = g_slist_append(session->streams, stream);
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+}
+
+static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
+				struct setconf_req *req, unsigned int size)
+{
+	struct conf_rej rej;
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	uint8_t err, category = 0x00;
+	GSList *l;
+
+	if (size < sizeof(struct setconf_req)) {
+		error("Too short getcap request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	if (sep->stream) {
+		err = AVDTP_SEP_IN_USE;
+		goto failed;
+	}
+
+	stream = g_new0(struct avdtp_stream, 1);
+	stream->session = session;
+	stream->lsep = sep;
+	stream->rseid = req->int_seid;
+	stream->caps = caps_to_list(req->caps,
+					size - sizeof(struct setconf_req),
+					&stream->codec,
+					&stream->delay_reporting);
+
+	/*
+	 * Verify that the Media Transport capability's length = 0.
+	 * Reject otherwise
+	 */
+	for (l = stream->caps; l != NULL; l = g_slist_next(l)) {
+		struct avdtp_service_capability *cap = l->data;
+
+		if (cap->category == AVDTP_MEDIA_TRANSPORT &&
+							cap->length != 0) {
+			err = AVDTP_BAD_MEDIA_TRANSPORT_FORMAT;
+			goto failed_stream;
+		}
+	}
+
+	if (stream->delay_reporting && session->version < 0x0103)
+		session->version = 0x0103;
+
+	if (sep->ind && sep->ind->set_configuration) {
+		if (!sep->ind->set_configuration(session, sep, stream,
+							stream->caps,
+							setconf_cb,
+							sep->user_data)) {
+			err = AVDTP_UNSUPPORTED_CONFIGURATION;
+			category = 0x00;
+			goto failed_stream;
+		}
+	} else {
+		if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+					AVDTP_SET_CONFIGURATION, NULL, 0)) {
+			stream_free(stream);
+			return FALSE;
+		}
+
+		sep->stream = stream;
+		sep->info.inuse = 1;
+		session->streams = g_slist_append(session->streams, stream);
+
+		avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+	}
+
+	return TRUE;
+
+failed_stream:
+	stream_free(stream);
+failed:
+	rej.error = err;
+	rej.category = category;
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+				AVDTP_SET_CONFIGURATION, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
+					struct seid_req *req, int size)
+{
+	GSList *l;
+	struct avdtp_local_sep *sep = NULL;
+	int rsp_size;
+	uint8_t err;
+	uint8_t buf[1024];
+	uint8_t *ptr = buf;
+
+	if (size < (int) sizeof(struct seid_req)) {
+		error("Too short getconf request");
+		return FALSE;
+	}
+
+	memset(buf, 0, sizeof(buf));
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+	if (!sep->stream || !sep->stream->caps) {
+		err = AVDTP_UNSUPPORTED_CONFIGURATION;
+		goto failed;
+	}
+
+	for (l = sep->stream->caps, rsp_size = 0; l; l = g_slist_next(l)) {
+		struct avdtp_service_capability *cap = l->data;
+
+		if (rsp_size + cap->length + 2 > (int) sizeof(buf))
+			break;
+
+		memcpy(ptr, cap, cap->length + 2);
+		rsp_size += cap->length + 2;
+		ptr += cap->length + 2;
+	}
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+				AVDTP_GET_CONFIGURATION, buf, rsp_size);
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+				AVDTP_GET_CONFIGURATION, &err, sizeof(err));
+}
+
+static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction,
+					struct seid_req *req, int size)
+{
+	struct conf_rej rej;
+
+	rej.error = AVDTP_NOT_SUPPORTED_COMMAND;
+	rej.category = 0x00;
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+					AVDTP_RECONFIGURE, &rej, sizeof(rej));
+}
+
+static void check_seid_collision(struct pending_req *req, uint8_t id)
+{
+	struct seid_req *seid = req->data;
+
+	if (seid->acp_seid == id)
+		req->collided = TRUE;
+}
+
+static void check_start_collision(struct pending_req *req, uint8_t id)
+{
+	struct start_req *start = req->data;
+	struct seid *seid = &start->first_seid;
+	int count = 1 + req->data_size - sizeof(struct start_req);
+	int i;
+
+	for (i = 0; i < count; i++, seid++) {
+		if (seid->seid == id) {
+			req->collided = TRUE;
+			return;
+		}
+	}
+}
+
+static void check_suspend_collision(struct pending_req *req, uint8_t id)
+{
+	struct suspend_req *suspend = req->data;
+	struct seid *seid = &suspend->first_seid;
+	int count = 1 + req->data_size - sizeof(struct suspend_req);
+	int i;
+
+	for (i = 0; i < count; i++, seid++) {
+		if (seid->seid == id) {
+			req->collided = TRUE;
+			return;
+		}
+	}
+}
+
+static void avdtp_check_collision(struct avdtp *session, uint8_t cmd,
+					struct avdtp_stream *stream)
+{
+	struct pending_req *req = session->req;
+
+	if (req == NULL || (req->signal_id != cmd && cmd != AVDTP_ABORT))
+		return;
+
+	if (cmd == AVDTP_ABORT)
+		cmd = req->signal_id;
+
+	switch (cmd) {
+	case AVDTP_OPEN:
+	case AVDTP_CLOSE:
+		check_seid_collision(req, stream->rseid);
+		break;
+	case AVDTP_START:
+		check_start_collision(req, stream->rseid);
+		break;
+	case AVDTP_SUSPEND:
+		check_suspend_collision(req, stream->rseid);
+		break;
+	}
+}
+
+static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
+				struct seid_req *req, unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	uint8_t err;
+
+	if (size < sizeof(struct seid_req)) {
+		error("Too short abort request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	if (sep->state != AVDTP_STATE_CONFIGURED) {
+		err = AVDTP_BAD_STATE;
+		goto failed;
+	}
+
+	stream = sep->stream;
+
+	if (sep->ind && sep->ind->open) {
+		if (!sep->ind->open(session, sep, stream, &err,
+					sep->user_data))
+			goto failed;
+	}
+
+	avdtp_check_collision(session, AVDTP_OPEN, stream);
+
+	if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_OPEN, NULL, 0))
+		return FALSE;
+
+	stream->open_acp = TRUE;
+	session->pending_open = stream;
+	stream->timer = g_timeout_add_seconds(REQ_TIMEOUT,
+						stream_open_timeout,
+						stream);
+
+	return TRUE;
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+				AVDTP_OPEN, &err, sizeof(err));
+}
+
+static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
+				struct start_req *req, unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	struct stream_rej rej;
+	struct seid *seid;
+	uint8_t err, failed_seid;
+	int seid_count, i;
+
+	if (size < sizeof(struct start_req)) {
+		error("Too short start request");
+		return FALSE;
+	}
+
+	seid_count = 1 + size - sizeof(struct start_req);
+
+	seid = &req->first_seid;
+
+	for (i = 0; i < seid_count; i++, seid++) {
+		failed_seid = seid->seid;
+
+		sep = find_local_sep_by_seid(session, seid->seid);
+		if (!sep || !sep->stream) {
+			err = AVDTP_BAD_ACP_SEID;
+			goto failed;
+		}
+
+		stream = sep->stream;
+
+		/* Also reject start cmd if state is not open */
+		if (sep->state != AVDTP_STATE_OPEN) {
+			err = AVDTP_BAD_STATE;
+			goto failed;
+		}
+		stream->starting = TRUE;
+
+		if (sep->ind && sep->ind->start) {
+			if (!sep->ind->start(session, sep, stream, &err,
+						sep->user_data))
+				goto failed;
+		}
+
+		avdtp_check_collision(session, AVDTP_START, stream);
+
+		avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+	}
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_START, NULL, 0);
+
+failed:
+	DBG("Rejecting (%d)", err);
+	memset(&rej, 0, sizeof(rej));
+	rej.acp_seid = failed_seid;
+	rej.error = err;
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+				AVDTP_START, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
+				struct seid_req *req, unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	uint8_t err;
+
+	if (size < sizeof(struct seid_req)) {
+		error("Too short close request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep || !sep->stream) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	if (sep->state != AVDTP_STATE_OPEN &&
+			sep->state != AVDTP_STATE_STREAMING) {
+		err = AVDTP_BAD_STATE;
+		goto failed;
+	}
+
+	stream = sep->stream;
+
+	if (sep->ind && sep->ind->close) {
+		if (!sep->ind->close(session, sep, stream, &err,
+					sep->user_data))
+			goto failed;
+	}
+
+	avdtp_check_collision(session, AVDTP_CLOSE, stream);
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+	if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_CLOSE, NULL, 0))
+		return FALSE;
+
+	stream->timer = g_timeout_add_seconds(REQ_TIMEOUT,
+					stream_close_timeout,
+					stream);
+
+	return TRUE;
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+					AVDTP_CLOSE, &err, sizeof(err));
+}
+
+static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
+				struct suspend_req *req, unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	struct stream_rej rej;
+	struct seid *seid;
+	uint8_t err, failed_seid;
+	int seid_count, i;
+
+	if (size < sizeof(struct suspend_req)) {
+		error("Too short suspend request");
+		return FALSE;
+	}
+
+	seid_count = 1 + size - sizeof(struct suspend_req);
+
+	seid = &req->first_seid;
+
+	for (i = 0; i < seid_count; i++, seid++) {
+		failed_seid = seid->seid;
+
+		sep = find_local_sep_by_seid(session, seid->seid);
+		if (!sep || !sep->stream) {
+			err = AVDTP_BAD_ACP_SEID;
+			goto failed;
+		}
+
+		stream = sep->stream;
+
+		if (sep->state != AVDTP_STATE_STREAMING) {
+			err = AVDTP_BAD_STATE;
+			goto failed;
+		}
+
+		if (sep->ind && sep->ind->suspend) {
+			if (!sep->ind->suspend(session, sep, stream, &err,
+						sep->user_data))
+				goto failed;
+		}
+
+		avdtp_check_collision(session, AVDTP_SUSPEND, stream);
+
+		avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+	}
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_SUSPEND, NULL, 0);
+
+failed:
+	memset(&rej, 0, sizeof(rej));
+	rej.acp_seid = failed_seid;
+	rej.error = err;
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+				AVDTP_SUSPEND, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
+				struct seid_req *req, unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	uint8_t err;
+	gboolean ret;
+
+	if (size < sizeof(struct seid_req)) {
+		error("Too short abort request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep || !sep->stream)
+		return TRUE;
+
+	if (sep->ind && sep->ind->abort)
+		sep->ind->abort(session, sep, sep->stream, &err,
+							sep->user_data);
+
+	avdtp_check_collision(session, AVDTP_ABORT, sep->stream);
+
+	ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_ABORT, NULL, 0);
+	if (ret)
+		avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
+
+	return ret;
+}
+
+static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction,
+					struct seid_req *req, int size)
+{
+	return avdtp_unknown_cmd(session, transaction, AVDTP_SECURITY_CONTROL);
+}
+
+static gboolean avdtp_delayreport_cmd(struct avdtp *session,
+					uint8_t transaction,
+					struct delay_req *req,
+					unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	uint8_t err;
+
+	if (size < sizeof(struct delay_req)) {
+		error("Too short delay report request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session, req->acp_seid);
+	if (!sep || !sep->stream) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	stream = sep->stream;
+
+	switch (sep->state) {
+	case AVDTP_STATE_IDLE:
+	case AVDTP_STATE_ABORTING:
+	case AVDTP_STATE_CLOSING:
+		err = AVDTP_BAD_STATE;
+		goto failed;
+	case AVDTP_STATE_CONFIGURED:
+	case AVDTP_STATE_OPEN:
+	case AVDTP_STATE_STREAMING:
+	default:
+		break;
+	}
+
+	stream->delay = ntohs(req->delay);
+
+	if (sep->ind && sep->ind->delayreport) {
+		if (!sep->ind->delayreport(session, sep, stream->rseid,
+						stream->delay, &err,
+						sep->user_data))
+			goto failed;
+	}
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_DELAY_REPORT, NULL, 0);
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+					AVDTP_DELAY_REPORT, &err, sizeof(err));
+}
+
+static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction,
+				uint8_t signal_id, void *buf, int size)
+{
+	switch (signal_id) {
+	case AVDTP_DISCOVER:
+		DBG("Received DISCOVER_CMD");
+		return avdtp_discover_cmd(session, transaction, buf, size);
+	case AVDTP_GET_CAPABILITIES:
+		DBG("Received  GET_CAPABILITIES_CMD");
+		return avdtp_getcap_cmd(session, transaction, buf, size,
+									FALSE);
+	case AVDTP_GET_ALL_CAPABILITIES:
+		DBG("Received  GET_ALL_CAPABILITIES_CMD");
+		return avdtp_getcap_cmd(session, transaction, buf, size, TRUE);
+	case AVDTP_SET_CONFIGURATION:
+		DBG("Received SET_CONFIGURATION_CMD");
+		return avdtp_setconf_cmd(session, transaction, buf, size);
+	case AVDTP_GET_CONFIGURATION:
+		DBG("Received GET_CONFIGURATION_CMD");
+		return avdtp_getconf_cmd(session, transaction, buf, size);
+	case AVDTP_RECONFIGURE:
+		DBG("Received RECONFIGURE_CMD");
+		return avdtp_reconf_cmd(session, transaction, buf, size);
+	case AVDTP_OPEN:
+		DBG("Received OPEN_CMD");
+		return avdtp_open_cmd(session, transaction, buf, size);
+	case AVDTP_START:
+		DBG("Received START_CMD");
+		return avdtp_start_cmd(session, transaction, buf, size);
+	case AVDTP_CLOSE:
+		DBG("Received CLOSE_CMD");
+		return avdtp_close_cmd(session, transaction, buf, size);
+	case AVDTP_SUSPEND:
+		DBG("Received SUSPEND_CMD");
+		return avdtp_suspend_cmd(session, transaction, buf, size);
+	case AVDTP_ABORT:
+		DBG("Received ABORT_CMD");
+		return avdtp_abort_cmd(session, transaction, buf, size);
+	case AVDTP_SECURITY_CONTROL:
+		DBG("Received SECURITY_CONTROL_CMD");
+		return avdtp_secctl_cmd(session, transaction, buf, size);
+	case AVDTP_DELAY_REPORT:
+		DBG("Received DELAY_REPORT_CMD");
+		return avdtp_delayreport_cmd(session, transaction, buf, size);
+	default:
+		DBG("Received unknown request id %u", signal_id);
+		return avdtp_unknown_cmd(session, transaction, signal_id);
+	}
+}
+
+enum avdtp_parse_result { PARSE_ERROR, PARSE_FRAGMENT, PARSE_SUCCESS };
+
+static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session,
+							void *buf, size_t size)
+{
+	struct avdtp_common_header *header = buf;
+	struct avdtp_single_header *single = (void *) session->buf;
+	struct avdtp_start_header *start = (void *) session->buf;
+	void *payload;
+	gsize payload_size;
+
+	switch (header->packet_type) {
+	case AVDTP_PKT_TYPE_SINGLE:
+		if (size < sizeof(*single)) {
+			error("Received too small single packet (%zu bytes)",
+									size);
+			return PARSE_ERROR;
+		}
+		if (session->in.active) {
+			error("SINGLE: Invalid AVDTP packet fragmentation");
+			return PARSE_ERROR;
+		}
+
+		payload = session->buf + sizeof(*single);
+		payload_size = size - sizeof(*single);
+
+		session->in.active = TRUE;
+		session->in.data_size = 0;
+		session->in.no_of_packets = 1;
+		session->in.transaction = header->transaction;
+		session->in.message_type = header->message_type;
+		session->in.signal_id = single->signal_id;
+
+		break;
+	case AVDTP_PKT_TYPE_START:
+		if (size < sizeof(*start)) {
+			error("Received too small start packet (%zu bytes)",
+									size);
+			return PARSE_ERROR;
+		}
+		if (session->in.active) {
+			error("START: Invalid AVDTP packet fragmentation");
+			return PARSE_ERROR;
+		}
+
+		session->in.active = TRUE;
+		session->in.data_size = 0;
+		session->in.transaction = header->transaction;
+		session->in.message_type = header->message_type;
+		session->in.no_of_packets = start->no_of_packets;
+		session->in.signal_id = start->signal_id;
+
+		payload = session->buf + sizeof(*start);
+		payload_size = size - sizeof(*start);
+
+		break;
+	case AVDTP_PKT_TYPE_CONTINUE:
+		if (size < sizeof(struct avdtp_continue_header)) {
+			error("Received too small continue packet (%zu bytes)",
+									size);
+			return PARSE_ERROR;
+		}
+		if (!session->in.active) {
+			error("CONTINUE: Invalid AVDTP packet fragmentation");
+			return PARSE_ERROR;
+		}
+		if (session->in.transaction != header->transaction) {
+			error("Continue transaction id doesn't match");
+			return PARSE_ERROR;
+		}
+		if (session->in.no_of_packets <= 1) {
+			error("Too few continue packets");
+			return PARSE_ERROR;
+		}
+
+		payload = session->buf + sizeof(struct avdtp_continue_header);
+		payload_size = size - sizeof(struct avdtp_continue_header);
+
+		break;
+	case AVDTP_PKT_TYPE_END:
+		if (size < sizeof(struct avdtp_continue_header)) {
+			error("Received too small end packet (%zu bytes)",
+									size);
+			return PARSE_ERROR;
+		}
+		if (!session->in.active) {
+			error("END: Invalid AVDTP packet fragmentation");
+			return PARSE_ERROR;
+		}
+		if (session->in.transaction != header->transaction) {
+			error("End transaction id doesn't match");
+			return PARSE_ERROR;
+		}
+		if (session->in.no_of_packets > 1) {
+			error("Got an end packet too early");
+			return PARSE_ERROR;
+		}
+
+		payload = session->buf + sizeof(struct avdtp_continue_header);
+		payload_size = size - sizeof(struct avdtp_continue_header);
+
+		break;
+	default:
+		error("Invalid AVDTP packet type 0x%02X", header->packet_type);
+		return PARSE_ERROR;
+	}
+
+	if (session->in.data_size + payload_size >
+					sizeof(session->in.buf)) {
+		error("Not enough incoming buffer space!");
+		return PARSE_ERROR;
+	}
+
+	memcpy(session->in.buf + session->in.data_size, payload, payload_size);
+	session->in.data_size += payload_size;
+
+	if (session->in.no_of_packets > 1) {
+		session->in.no_of_packets--;
+		DBG("Received AVDTP fragment. %d to go",
+						session->in.no_of_packets);
+		return PARSE_FRAGMENT;
+	}
+
+	session->in.active = FALSE;
+
+	return PARSE_SUCCESS;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	struct avdtp *session = data;
+	struct avdtp_common_header *header;
+	ssize_t size;
+	int fd;
+
+	DBG("");
+
+	if (cond & G_IO_NVAL) {
+		session->io_id = 0;
+
+		return FALSE;
+	}
+
+	header = (void *) session->buf;
+
+	if (cond & (G_IO_HUP | G_IO_ERR))
+		goto failed;
+
+	fd = g_io_channel_unix_get_fd(chan);
+	size = read(fd, session->buf, session->imtu);
+	if (size < 0) {
+		error("IO Channel read error");
+		goto failed;
+	}
+
+	if ((size_t) size < sizeof(struct avdtp_common_header)) {
+		error("Received too small packet (%zu bytes)", size);
+		goto failed;
+	}
+
+	switch (avdtp_parse_data(session, session->buf, size)) {
+	case PARSE_ERROR:
+		goto failed;
+	case PARSE_FRAGMENT:
+		return TRUE;
+	case PARSE_SUCCESS:
+		break;
+	}
+
+	/* Take a reference to protect against callback destroying session */
+	avdtp_ref(session);
+
+	if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) {
+		if (!avdtp_parse_cmd(session, session->in.transaction,
+					session->in.signal_id,
+					session->in.buf,
+					session->in.data_size)) {
+			error("Unable to handle command. Disconnecting");
+			goto failed;
+		}
+
+		if (session->req && session->req->collided) {
+			DBG("Collision detected");
+			goto next;
+		}
+
+		avdtp_unref(session);
+		return TRUE;
+	}
+
+	if (session->req == NULL) {
+		error("No pending request, ignoring message");
+		avdtp_unref(session);
+		return TRUE;
+	}
+
+	if (header->transaction != session->req->transaction) {
+		error("Transaction label doesn't match");
+		avdtp_unref(session);
+		return TRUE;
+	}
+
+	if (session->in.signal_id != session->req->signal_id) {
+		error("Response signal doesn't match");
+		avdtp_unref(session);
+		return TRUE;
+	}
+
+	g_source_remove(session->req->timeout);
+	session->req->timeout = 0;
+
+	switch (header->message_type) {
+	case AVDTP_MSG_TYPE_ACCEPT:
+		if (!avdtp_parse_resp(session, session->req->stream,
+						session->in.transaction,
+						session->in.signal_id,
+						session->in.buf,
+						session->in.data_size)) {
+			error("Unable to parse accept response");
+			goto failed;
+		}
+		break;
+	case AVDTP_MSG_TYPE_REJECT:
+		if (!avdtp_parse_rej(session, session->req->stream,
+						session->in.transaction,
+						session->in.signal_id,
+						session->in.buf,
+						session->in.data_size)) {
+			error("Unable to parse reject response");
+			goto failed;
+		}
+		break;
+	case AVDTP_MSG_TYPE_GEN_REJECT:
+		error("Received a General Reject message");
+		break;
+	default:
+		error("Unknown message type 0x%02X", header->message_type);
+		break;
+	}
+
+next:
+	pending_req_free(session->req);
+	session->req = NULL;
+
+	if (session->ref > 1)
+		process_queue(session);
+
+	avdtp_unref(session);
+
+	return TRUE;
+
+failed:
+	session->io_id = 0;
+	connection_lost(session, EIO);
+
+	return FALSE;
+}
+
+static int set_priority(int fd, int priority)
+{
+	int err;
+
+	err = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority,
+							sizeof(priority));
+	if (err == 0 || errno == ENOTSOCK)
+		return 0;
+
+	err = -errno;
+	error("setsockopt(SO_PRIORITY): %s (%d)", strerror(-err), -err);
+
+	return err;
+}
+
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+							struct queue *lseps)
+{
+	struct avdtp *session;
+	GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	int new_fd;
+
+	if (!lseps)
+		return NULL;
+
+	new_fd = dup(fd);
+	if (new_fd < 0) {
+		error("dup(): %s (%d)", strerror(errno), errno);
+		return NULL;
+	}
+
+	if (set_priority(new_fd, 6) < 0)
+		return NULL;
+
+	session = g_new0(struct avdtp, 1);
+	session->io = g_io_channel_unix_new(new_fd);
+	session->version = version;
+	session->imtu = imtu;
+	session->omtu = omtu;
+	session->buf = g_malloc0(MAX(session->imtu, session->omtu));
+
+	/* This watch should be low priority since otherwise the
+	 * connect callback might be dispatched before the session
+	 * callback if the kernel wakes us up at the same time for
+	 * them. This could happen if a headset is very quick in
+	 * sending the Start command after connecting the stream
+	 * transport channel.
+	 */
+	session->io_id = g_io_add_watch_full(session->io, G_PRIORITY_LOW, cond,
+						(GIOFunc) session_cb, session,
+						NULL);
+
+	session->lseps = lseps;
+
+	return avdtp_ref(session);
+}
+
+unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
+						avdtp_disconnect_cb_t cb,
+						void *user_data)
+{
+	struct disconnect_callback *callback;
+	static unsigned int id = 0;
+
+	callback = g_new0(struct disconnect_callback, 1);
+	callback->id = ++id;
+	callback->cb = cb;
+	callback->user_data = user_data;
+	session->disconnect = g_slist_append(session->disconnect, callback);
+
+	return id;
+}
+
+gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id)
+{
+	GSList *l;
+
+	for (l = session->disconnect; l; l = g_slist_next(l)) {
+		struct disconnect_callback *callback = l->data;
+
+		if (callback->id != id)
+			continue;
+
+		session->disconnect = g_slist_remove(session->disconnect,
+								callback);
+		g_free(callback);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void avdtp_shutdown(struct avdtp *session)
+{
+	GSList *l;
+	bool aborting = false;
+
+	if (!session->io)
+		return;
+
+	for (l = session->streams; l; l = g_slist_next(l)) {
+		struct avdtp_stream *stream = l->data;
+
+		if (stream->abort_int ||
+					avdtp_close(session, stream, TRUE) == 0)
+			aborting = true;
+	}
+
+	if (aborting) {
+		/* defer shutdown until all streams are aborted properly */
+		session->shutdown = true;
+	} else {
+		int sock = g_io_channel_unix_get_fd(session->io);
+
+		shutdown(sock, SHUT_RDWR);
+	}
+}
+
+static void queue_request(struct avdtp *session, struct pending_req *req,
+			gboolean priority)
+{
+	if (priority)
+		session->prio_queue = g_slist_append(session->prio_queue, req);
+	else
+		session->req_queue = g_slist_append(session->req_queue, req);
+}
+
+static uint8_t req_get_seid(struct pending_req *req)
+{
+	if (req->signal_id == AVDTP_DISCOVER)
+		return 0;
+
+	return ((struct seid_req *) (req->data))->acp_seid;
+}
+
+static int cancel_request(struct avdtp *session, int err)
+{
+	struct pending_req *req;
+	struct seid_req sreq;
+	struct avdtp_local_sep *lsep;
+	struct avdtp_stream *stream;
+	uint8_t seid;
+	struct avdtp_error averr;
+
+	req = session->req;
+	session->req = NULL;
+
+	avdtp_error_init(&averr, AVDTP_ERRNO, err);
+
+	seid = req_get_seid(req);
+	if (seid)
+		stream = find_stream_by_rseid(session, seid);
+	else
+		stream = NULL;
+
+	if (stream) {
+		stream->abort_int = TRUE;
+		lsep = stream->lsep;
+	} else
+		lsep = NULL;
+
+	switch (req->signal_id) {
+	case AVDTP_RECONFIGURE:
+		error("Reconfigure: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+			lsep->cfm->reconfigure(session, lsep, stream, &averr,
+						lsep->user_data);
+		break;
+	case AVDTP_OPEN:
+		error("Open: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->open)
+			lsep->cfm->open(session, lsep, stream, &averr,
+					lsep->user_data);
+		break;
+	case AVDTP_START:
+		error("Start: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->start) {
+			lsep->cfm->start(session, lsep, stream, &averr,
+						lsep->user_data);
+			if (stream)
+				stream->starting = FALSE;
+		}
+		break;
+	case AVDTP_SUSPEND:
+		error("Suspend: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->suspend)
+			lsep->cfm->suspend(session, lsep, stream, &averr,
+						lsep->user_data);
+		break;
+	case AVDTP_CLOSE:
+		error("Close: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->close) {
+			lsep->cfm->close(session, lsep, stream, &averr,
+						lsep->user_data);
+			if (stream)
+				stream->close_int = FALSE;
+		}
+		break;
+	case AVDTP_SET_CONFIGURATION:
+		error("SetConfiguration: %s (%d)", strerror(err), err);
+		if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+			lsep->cfm->set_configuration(session, lsep, stream,
+						&averr, lsep->user_data);
+		goto failed;
+	case AVDTP_DISCOVER:
+		error("Discover: %s (%d)", strerror(err), err);
+		goto failed;
+	case AVDTP_GET_CAPABILITIES:
+		error("GetCapabilities: %s (%d)", strerror(err), err);
+		goto failed;
+	case AVDTP_ABORT:
+		error("Abort: %s (%d)", strerror(err), err);
+		goto failed;
+	}
+
+	if (!stream)
+		goto failed;
+
+	memset(&sreq, 0, sizeof(sreq));
+	sreq.acp_seid = seid;
+
+	err = send_request(session, TRUE, stream, AVDTP_ABORT, &sreq,
+				sizeof(sreq));
+	if (err < 0) {
+		error("Unable to send abort request");
+		goto failed;
+	}
+
+	goto done;
+
+failed:
+	connection_lost(session, err);
+done:
+	pending_req_free(req);
+	return err;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+	struct avdtp *session = user_data;
+
+	cancel_request(session, ETIMEDOUT);
+
+	return FALSE;
+}
+
+static int send_req(struct avdtp *session, gboolean priority,
+			struct pending_req *req)
+{
+	static int transaction = 0;
+	int err;
+
+	if (session->req != NULL) {
+		queue_request(session, req, priority);
+		return 0;
+	}
+
+	req->transaction = transaction++;
+	transaction %= 16;
+
+	/* FIXME: Should we retry to send if the buffer
+	was not totally sent or in case of EINTR? */
+	if (!avdtp_send(session, req->transaction, AVDTP_MSG_TYPE_COMMAND,
+				req->signal_id, req->data, req->data_size)) {
+		err = -EIO;
+		goto failed;
+	}
+
+	session->req = req;
+
+	req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ?
+					ABORT_TIMEOUT : REQ_TIMEOUT,
+					request_timeout,
+					session);
+	return 0;
+
+failed:
+	g_free(req->data);
+	g_free(req);
+	return err;
+}
+
+static int send_request(struct avdtp *session, gboolean priority,
+			struct avdtp_stream *stream, uint8_t signal_id,
+			void *buffer, size_t size)
+{
+	struct pending_req *req;
+
+	if (size > 0 && !buffer) {
+		DBG("Invalid buffer %p", buffer);
+		return -EINVAL;
+	}
+
+	if (stream && stream->abort_int && signal_id != AVDTP_ABORT) {
+		DBG("Unable to send requests while aborting");
+		return -EINVAL;
+	}
+
+	req = g_new0(struct pending_req, 1);
+	req->signal_id = signal_id;
+	req->data_size = size;
+	req->stream = stream;
+
+	if (size > 0) {
+		req->data = g_malloc(size);
+		memcpy(req->data, buffer, size);
+	}
+
+	return send_req(session, priority, req);
+}
+
+static gboolean avdtp_discover_resp(struct avdtp *session,
+					struct discover_resp *resp, int size)
+{
+	int sep_count, i;
+	uint8_t getcap_cmd;
+	int ret = 0;
+	gboolean getcap_pending = FALSE;
+
+	if (session->version >= 0x0103)
+		getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
+	else
+		getcap_cmd = AVDTP_GET_CAPABILITIES;
+
+	sep_count = size / sizeof(struct seid_info);
+
+	for (i = 0; i < sep_count; i++) {
+		struct avdtp_remote_sep *sep;
+		struct avdtp_stream *stream;
+		struct seid_req req;
+
+		DBG("seid %d type %d media %d in use %d",
+				resp->seps[i].seid, resp->seps[i].type,
+				resp->seps[i].media_type, resp->seps[i].inuse);
+
+		stream = find_stream_by_rseid(session, resp->seps[i].seid);
+
+		sep = find_remote_sep(session->seps, resp->seps[i].seid);
+		if (!sep) {
+			if (resp->seps[i].inuse && !stream)
+				continue;
+			sep = g_new0(struct avdtp_remote_sep, 1);
+			session->seps = g_slist_append(session->seps, sep);
+		}
+
+		sep->stream = stream;
+		sep->seid = resp->seps[i].seid;
+		sep->type = resp->seps[i].type;
+		sep->media_type = resp->seps[i].media_type;
+
+		memset(&req, 0, sizeof(req));
+		req.acp_seid = sep->seid;
+
+		ret = send_request(session, TRUE, NULL, getcap_cmd,
+							&req, sizeof(req));
+		if (ret < 0)
+			break;
+		getcap_pending = TRUE;
+	}
+
+	if (!getcap_pending)
+		finalize_discovery(session, -ret);
+
+	return TRUE;
+}
+
+static gboolean avdtp_get_capabilities_resp(struct avdtp *session,
+						struct getcap_resp *resp,
+						unsigned int size)
+{
+	struct avdtp_remote_sep *sep;
+	uint8_t seid;
+
+	/* Check for minimum required packet size includes:
+	 *   1. getcap resp header
+	 *   2. media transport capability (2 bytes)
+	 *   3. media codec capability type + length (2 bytes)
+	 *   4. the actual media codec elements
+	 * */
+	if (size < (sizeof(struct getcap_resp) + 4 +
+				sizeof(struct avdtp_media_codec_capability))) {
+		error("Too short getcap resp packet");
+		return FALSE;
+	}
+
+	seid = ((struct seid_req *) session->req->data)->acp_seid;
+
+	sep = find_remote_sep(session->seps, seid);
+
+	DBG("seid %d type %d media %d", sep->seid,
+					sep->type, sep->media_type);
+
+	if (sep->caps) {
+		g_slist_free_full(sep->caps, g_free);
+		sep->caps = NULL;
+		sep->codec = NULL;
+		sep->delay_reporting = FALSE;
+	}
+
+	sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
+					&sep->codec, &sep->delay_reporting);
+
+	return TRUE;
+}
+
+static gboolean avdtp_set_configuration_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					struct avdtp_single_header *resp,
+					int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+
+	if (sep->cfm && sep->cfm->set_configuration)
+		sep->cfm->set_configuration(session, sep, stream, NULL,
+						sep->user_data);
+
+	return TRUE;
+}
+
+static gboolean avdtp_reconfigure_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					struct avdtp_single_header *resp,
+					int size)
+{
+	return TRUE;
+}
+
+static gboolean avdtp_open_resp(struct avdtp *session,
+				struct avdtp_stream *stream,
+				struct seid_rej *resp, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	session->pending_open = stream;
+
+	if (!stream->open_acp && sep->cfm && sep->cfm->open)
+		sep->cfm->open(session, sep, stream, NULL, sep->user_data);
+
+	return TRUE;
+}
+
+static gboolean avdtp_start_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					struct seid_rej *resp, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	/* We might be in STREAMING already if both sides send START_CMD at the
+	 * same time and the one in SNK role doesn't reject it as it should */
+	if (sep->state != AVDTP_STATE_STREAMING)
+		avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+
+	if (sep->cfm && sep->cfm->start)
+		sep->cfm->start(session, sep, stream, NULL, sep->user_data);
+
+	return TRUE;
+}
+
+static gboolean avdtp_close_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					struct seid_rej *resp, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+	close_stream(stream);
+
+	return TRUE;
+}
+
+static gboolean avdtp_suspend_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					void *data, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+	if (sep->cfm && sep->cfm->suspend)
+		sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);
+
+	return TRUE;
+}
+
+static gboolean avdtp_abort_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					struct seid_rej *resp, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
+
+	if (sep->cfm && sep->cfm->abort)
+		sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+	avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+
+	return TRUE;
+}
+
+static gboolean avdtp_delay_report_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					void *data, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	if (sep->cfm && sep->cfm->delay_report)
+		sep->cfm->delay_report(session, sep, stream, NULL,
+							sep->user_data);
+
+	return TRUE;
+}
+
+static gboolean avdtp_parse_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					uint8_t transaction, uint8_t signal_id,
+					void *buf, int size)
+{
+	struct pending_req *next;
+	const char *get_all = "";
+
+	if (session->prio_queue)
+		next = session->prio_queue->data;
+	else if (session->req_queue)
+		next = session->req_queue->data;
+	else
+		next = NULL;
+
+	switch (signal_id) {
+	case AVDTP_DISCOVER:
+		DBG("DISCOVER request succeeded");
+		return avdtp_discover_resp(session, buf, size);
+	case AVDTP_GET_ALL_CAPABILITIES:
+		get_all = "ALL_";
+	case AVDTP_GET_CAPABILITIES:
+		DBG("GET_%sCAPABILITIES request succeeded", get_all);
+		if (!avdtp_get_capabilities_resp(session, buf, size))
+			return FALSE;
+		if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES ||
+				next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
+			finalize_discovery(session, 0);
+		return TRUE;
+	}
+
+	/* The remaining commands require an existing stream so bail out
+	 * here if the stream got unexpectedly disconnected */
+	if (!stream) {
+		DBG("AVDTP: stream was closed while waiting for reply");
+		return TRUE;
+	}
+
+	switch (signal_id) {
+	case AVDTP_SET_CONFIGURATION:
+		DBG("SET_CONFIGURATION request succeeded");
+		return avdtp_set_configuration_resp(session, stream,
+								buf, size);
+	case AVDTP_RECONFIGURE:
+		DBG("RECONFIGURE request succeeded");
+		return avdtp_reconfigure_resp(session, stream, buf, size);
+	case AVDTP_OPEN:
+		DBG("OPEN request succeeded");
+		return avdtp_open_resp(session, stream, buf, size);
+	case AVDTP_SUSPEND:
+		DBG("SUSPEND request succeeded");
+		return avdtp_suspend_resp(session, stream, buf, size);
+	case AVDTP_START:
+		DBG("START request succeeded");
+		return avdtp_start_resp(session, stream, buf, size);
+	case AVDTP_CLOSE:
+		DBG("CLOSE request succeeded");
+		return avdtp_close_resp(session, stream, buf, size);
+	case AVDTP_ABORT:
+		DBG("ABORT request succeeded");
+		return avdtp_abort_resp(session, stream, buf, size);
+	case AVDTP_DELAY_REPORT:
+		DBG("DELAY_REPORT request succeeded");
+		return avdtp_delay_report_resp(session, stream, buf, size);
+	}
+
+	error("Unknown signal id in accept response: %u", signal_id);
+	return TRUE;
+}
+
+static gboolean seid_rej_to_err(struct seid_rej *rej, unsigned int size,
+					struct avdtp_error *err)
+{
+	if (size < sizeof(struct seid_rej)) {
+		error("Too small packet for seid_rej");
+		return FALSE;
+	}
+
+	avdtp_error_init(err, 0x00, rej->error);
+
+	return TRUE;
+}
+
+static gboolean conf_rej_to_err(struct conf_rej *rej, unsigned int size,
+				struct avdtp_error *err)
+{
+	if (size < sizeof(struct conf_rej)) {
+		error("Too small packet for conf_rej");
+		return FALSE;
+	}
+
+	avdtp_error_init(err, rej->category, rej->error);
+
+	return TRUE;
+}
+
+static gboolean stream_rej_to_err(struct stream_rej *rej, unsigned int size,
+					struct avdtp_error *err,
+					uint8_t *acp_seid)
+{
+	if (size < sizeof(struct stream_rej)) {
+		error("Too small packet for stream_rej");
+		return FALSE;
+	}
+
+	avdtp_error_init(err, 0x00, rej->error);
+
+	if (acp_seid)
+		*acp_seid = rej->acp_seid;
+
+	return TRUE;
+}
+
+static gboolean avdtp_parse_rej(struct avdtp *session,
+					struct avdtp_stream *stream,
+					uint8_t transaction, uint8_t signal_id,
+					void *buf, int size)
+{
+	struct avdtp_error err;
+	uint8_t acp_seid;
+	struct avdtp_local_sep *sep = stream ? stream->lsep : NULL;
+
+	switch (signal_id) {
+	case AVDTP_DISCOVER:
+	case AVDTP_GET_CAPABILITIES:
+	case AVDTP_GET_ALL_CAPABILITIES:
+		if (!seid_rej_to_err(buf, size, &err))
+			return FALSE;
+		error("%s request rejected: %s (%d)",
+			signal_id == AVDTP_DISCOVER ? "DISCOVER" :
+			signal_id == AVDTP_GET_CAPABILITIES ?
+			"GET_CAPABILITIES" : "GET_ALL_CAPABILITIES",
+			avdtp_strerror(&err), err.err.error_code);
+		if (session->discover) {
+			session->discover->cb(session, session->seps, &err,
+						session->discover->user_data);
+			g_free(session->discover);
+			session->discover = NULL;
+		}
+		return TRUE;
+	case AVDTP_OPEN:
+		if (!seid_rej_to_err(buf, size, &err))
+			return FALSE;
+		error("OPEN request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->open)
+			sep->cfm->open(session, sep, stream, &err,
+					sep->user_data);
+		return TRUE;
+	case AVDTP_SET_CONFIGURATION:
+		if (!conf_rej_to_err(buf, size, &err))
+			return FALSE;
+		error("SET_CONFIGURATION request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->set_configuration)
+			sep->cfm->set_configuration(session, sep, stream,
+							&err, sep->user_data);
+		return TRUE;
+	case AVDTP_GET_CONFIGURATION:
+		if (!seid_rej_to_err(buf, size, &err))
+			return FALSE;
+		error("GET_CONFIGURATION request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->get_configuration)
+			sep->cfm->get_configuration(session, sep, stream, &err,
+								sep->user_data);
+		return TRUE;
+	case AVDTP_RECONFIGURE:
+		if (!conf_rej_to_err(buf, size, &err))
+			return FALSE;
+		error("RECONFIGURE request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->reconfigure)
+			sep->cfm->reconfigure(session, sep, stream, &err,
+						sep->user_data);
+		return TRUE;
+	case AVDTP_START:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("START request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->start) {
+			stream->starting = FALSE;
+			sep->cfm->start(session, sep, stream, &err,
+					sep->user_data);
+		}
+		return TRUE;
+	case AVDTP_SUSPEND:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("SUSPEND request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->suspend)
+			sep->cfm->suspend(session, sep, stream, &err,
+						sep->user_data);
+		return TRUE;
+	case AVDTP_CLOSE:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("CLOSE request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->close) {
+			sep->cfm->close(session, sep, stream, &err,
+					sep->user_data);
+			stream->close_int = FALSE;
+		}
+		return TRUE;
+	case AVDTP_ABORT:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("ABORT request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->abort)
+			sep->cfm->abort(session, sep, stream, &err,
+					sep->user_data);
+		return FALSE;
+	case AVDTP_DELAY_REPORT:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("DELAY_REPORT request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->delay_report)
+			sep->cfm->delay_report(session, sep, stream, &err,
+							sep->user_data);
+		return TRUE;
+	default:
+		error("Unknown reject response signal id: %u", signal_id);
+		return TRUE;
+	}
+}
+
+struct avdtp_service_capability *avdtp_stream_get_codec(
+						struct avdtp_stream *stream)
+{
+	GSList *l;
+
+	for (l = stream->caps; l; l = l->next) {
+		struct avdtp_service_capability *cap = l->data;
+
+		if (cap->category == AVDTP_MEDIA_CODEC)
+			return cap;
+	}
+
+	return NULL;
+}
+
+static gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
+					struct avdtp_service_capability *cap)
+{
+	GSList *l;
+	struct avdtp_service_capability *stream_cap;
+
+	for (l = stream->caps; l; l = g_slist_next(l)) {
+		stream_cap = l->data;
+
+		if (stream_cap->category != cap->category ||
+			stream_cap->length != cap->length)
+			continue;
+
+		if (memcmp(stream_cap->data, cap->data, cap->length) == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+					GSList *caps)
+{
+	for (; caps; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+
+		if (!avdtp_stream_has_capability(stream, cap))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+						struct avdtp_stream *stream)
+{
+	GSList *l;
+
+	for (l = stream->session->seps; l; l = l->next) {
+		struct avdtp_remote_sep *sep = l->data;
+
+		if (sep->seid == stream->rseid)
+			return sep;
+	}
+
+	return NULL;
+}
+
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+						size_t imtu, size_t omtu)
+{
+	GIOChannel *io;
+
+	if (stream != stream->session->pending_open)
+		return FALSE;
+
+	if (set_priority(fd, 5) < 0)
+		return FALSE;
+
+	io = g_io_channel_unix_new(fd);
+
+	handle_transport_connect(stream->session, io, imtu, omtu);
+
+	g_io_channel_unref(io);
+
+	return TRUE;
+}
+
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+					uint16_t *imtu, uint16_t *omtu,
+					GSList **caps)
+{
+	if (stream->io == NULL)
+		return FALSE;
+
+	if (sock)
+		*sock = g_io_channel_unix_get_fd(stream->io);
+
+	if (omtu)
+		*omtu = stream->omtu;
+
+	if (imtu)
+		*imtu = stream->imtu;
+
+	if (caps)
+		*caps = stream->caps;
+
+	return TRUE;
+}
+
+static int process_queue(struct avdtp *session)
+{
+	GSList **queue, *l;
+	struct pending_req *req;
+
+	if (session->req)
+		return 0;
+
+	if (session->prio_queue)
+		queue = &session->prio_queue;
+	else
+		queue = &session->req_queue;
+
+	if (!*queue)
+		return 0;
+
+	l = *queue;
+	req = l->data;
+
+	*queue = g_slist_remove(*queue, req);
+
+	return send_req(session, FALSE, req);
+}
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep)
+{
+	return sep->codec;
+}
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+							const void *data,
+							int length)
+{
+	struct avdtp_service_capability *cap;
+
+	if (category < AVDTP_MEDIA_TRANSPORT ||
+					category > AVDTP_DELAY_REPORTING)
+		return NULL;
+
+	if (length > 0 && !data)
+		return NULL;
+
+	cap = g_malloc(sizeof(struct avdtp_service_capability) + length);
+	cap->category = category;
+	cap->length = length;
+
+	if (length > 0)
+		memcpy(cap->data, data, length);
+
+	return cap;
+}
+
+static gboolean process_discover(gpointer data)
+{
+	struct avdtp *session = data;
+
+	session->discover->id = 0;
+
+	finalize_discovery(session, 0);
+
+	return FALSE;
+}
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+			void *user_data)
+{
+	int err;
+
+	if (session->discover)
+		return -EBUSY;
+
+	session->discover = g_new0(struct discover_callback, 1);
+
+	if (session->seps) {
+		session->discover->cb = cb;
+		session->discover->user_data = user_data;
+		session->discover->id = g_idle_add(process_discover, session);
+		return 0;
+	}
+
+	err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
+	if (err == 0) {
+		session->discover->cb = cb;
+		session->discover->user_data = user_data;
+	}
+
+	return err;
+}
+
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+				struct avdtp_stream *stream,
+				unsigned int id)
+{
+	GSList *l;
+	struct stream_callback *cb;
+
+	if (!stream)
+		return FALSE;
+
+	for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) {
+		struct stream_callback *tmp = l->data;
+		if (tmp && tmp->id == id) {
+			cb = tmp;
+			break;
+		}
+	}
+
+	if (!cb)
+		return FALSE;
+
+	stream->callbacks = g_slist_remove(stream->callbacks, cb);
+	g_free(cb);
+
+	return TRUE;
+}
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+					struct avdtp_stream *stream,
+					avdtp_stream_state_cb cb, void *data)
+{
+	struct stream_callback *stream_cb;
+	static unsigned int id = 0;
+
+	stream_cb = g_new(struct stream_callback, 1);
+	stream_cb->cb = cb;
+	stream_cb->user_data = data;
+	stream_cb->id = ++id;
+
+	stream->callbacks = g_slist_append(stream->callbacks, stream_cb);
+
+	return stream_cb->id;
+}
+
+int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream)
+{
+	struct seid_req req;
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+
+	return send_request(session, FALSE, stream, AVDTP_GET_CONFIGURATION,
+							&req, sizeof(req));
+}
+
+static void copy_capabilities(gpointer data, gpointer user_data)
+{
+	struct avdtp_service_capability *src_cap = data;
+	struct avdtp_service_capability *dst_cap;
+	GSList **l = user_data;
+
+	dst_cap = avdtp_service_cap_new(src_cap->category, src_cap->data,
+					src_cap->length);
+
+	*l = g_slist_append(*l, dst_cap);
+}
+
+int avdtp_set_configuration(struct avdtp *session,
+				struct avdtp_remote_sep *rsep,
+				struct avdtp_local_sep *lsep,
+				GSList *caps,
+				struct avdtp_stream **stream)
+{
+	struct setconf_req *req;
+	struct avdtp_stream *new_stream;
+	unsigned char *ptr;
+	int err, caps_len;
+	struct avdtp_service_capability *cap;
+	GSList *l;
+
+	if (!(lsep && rsep))
+		return -EINVAL;
+
+	DBG("%p: int_seid=%u, acp_seid=%u", session,
+			lsep->info.seid, rsep->seid);
+
+	new_stream = g_new0(struct avdtp_stream, 1);
+	new_stream->session = session;
+	new_stream->lsep = lsep;
+	new_stream->rseid = rsep->seid;
+
+	if (rsep->delay_reporting && lsep->delay_reporting) {
+		struct avdtp_service_capability *delay_reporting;
+
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		caps = g_slist_append(caps, delay_reporting);
+		new_stream->delay_reporting = TRUE;
+	}
+
+	g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
+
+	/* Calculate total size of request */
+	for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
+		cap = l->data;
+		caps_len += cap->length + 2;
+	}
+
+	req = g_malloc0(sizeof(struct setconf_req) + caps_len);
+
+	req->int_seid = lsep->info.seid;
+	req->acp_seid = rsep->seid;
+
+	/* Copy the capabilities into the request */
+	for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
+		cap = l->data;
+		memcpy(ptr, cap, cap->length + 2);
+		ptr += cap->length + 2;
+	}
+
+	err = send_request(session, FALSE, new_stream,
+				AVDTP_SET_CONFIGURATION, req,
+				sizeof(struct setconf_req) + caps_len);
+	if (err < 0)
+		stream_free(new_stream);
+	else {
+		lsep->info.inuse = 1;
+		lsep->stream = new_stream;
+		rsep->stream = new_stream;
+		session->streams = g_slist_append(session->streams, new_stream);
+		if (stream)
+			*stream = new_stream;
+	}
+
+	g_free(req);
+
+	return err;
+}
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream)
+{
+	struct seid_req req;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state > AVDTP_STATE_CONFIGURED)
+		return -EINVAL;
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+
+	return send_request(session, FALSE, stream, AVDTP_OPEN,
+							&req, sizeof(req));
+}
+
+static gboolean start_timeout(gpointer user_data)
+{
+	struct avdtp_stream *stream = user_data;
+	struct avdtp *session = stream->session;
+
+	stream->open_acp = FALSE;
+
+	if (avdtp_start(session, stream) < 0)
+		error("wait_timeout: avdtp_start failed");
+
+	stream->start_timer = 0;
+
+	return FALSE;
+}
+
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
+{
+	struct start_req req;
+	int ret;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state != AVDTP_STATE_OPEN)
+		return -EINVAL;
+
+	/* Recommendation 12:
+	 *  If the RD has configured and opened a stream it is also responsible
+	 *  to start the streaming via GAVDP_START.
+	 */
+	if (stream->open_acp) {
+		/* If timer already active wait it */
+		if (stream->start_timer)
+			return 0;
+
+		stream->start_timer = g_timeout_add_seconds(START_TIMEOUT,
+								start_timeout,
+								stream);
+		return 0;
+	}
+
+	if (stream->close_int == TRUE) {
+		error("avdtp_start: rejecting start since close is initiated");
+		return -EINVAL;
+	}
+
+	if (stream->starting == TRUE) {
+		DBG("stream already started");
+		return -EINPROGRESS;
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.first_seid.seid = stream->rseid;
+
+	ret = send_request(session, FALSE, stream, AVDTP_START,
+							&req, sizeof(req));
+	if (ret == 0)
+		stream->starting = TRUE;
+
+	return ret;
+}
+
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+		gboolean immediate)
+{
+	struct seid_req req;
+	int ret;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->close_int == TRUE) {
+		error("avdtp_close: rejecting since close is already initiated");
+		return -EINVAL;
+	}
+
+	/* If stream is not yet in the OPEN state, let's use ABORT_CMD */
+	if (stream->lsep->state < AVDTP_STATE_OPEN)
+		return avdtp_abort(session, stream);
+
+	if (immediate && session->req && stream == session->req->stream)
+		return avdtp_abort(session, stream);
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+
+	ret = send_request(session, FALSE, stream, AVDTP_CLOSE,
+							&req, sizeof(req));
+	if (ret == 0)
+		stream->close_int = TRUE;
+
+	return ret;
+}
+
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream)
+{
+	struct seid_req req;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state <= AVDTP_STATE_OPEN || stream->close_int)
+		return -EINVAL;
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+
+	return send_request(session, FALSE, stream, AVDTP_SUSPEND,
+							&req, sizeof(req));
+}
+
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
+{
+	struct seid_req req;
+	int ret;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state == AVDTP_STATE_ABORTING)
+		return -EINVAL;
+
+	if (session->req && session->req->timeout > 0 &&
+						stream == session->req->stream)
+		return cancel_request(session, ECANCELED);
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+
+	ret = send_request(session, TRUE, stream, AVDTP_ABORT,
+							&req, sizeof(req));
+	if (ret == 0)
+		stream->abort_int = TRUE;
+
+	return ret;
+}
+
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+							uint16_t delay)
+{
+	struct delay_req req;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state != AVDTP_STATE_CONFIGURED &&
+				stream->lsep->state != AVDTP_STATE_STREAMING)
+		return -EINVAL;
+
+	if (!stream->delay_reporting || session->version < 0x0103)
+		return -EINVAL;
+
+	stream->delay = delay;
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+	req.delay = htons(delay);
+
+	return send_request(session, TRUE, stream, AVDTP_DELAY_REPORT,
+							&req, sizeof(req));
+}
+
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+						uint8_t media_type,
+						uint8_t codec_type,
+						gboolean delay_reporting,
+						struct avdtp_sep_ind *ind,
+						struct avdtp_sep_cfm *cfm,
+						void *user_data)
+{
+	struct avdtp_local_sep *sep;
+	uint8_t seid = util_get_uid(&seids, MAX_SEID);
+
+	if (!seid)
+		return NULL;
+
+	sep = g_new0(struct avdtp_local_sep, 1);
+
+	sep->state = AVDTP_STATE_IDLE;
+	sep->info.seid = seid;
+	sep->info.type = type;
+	sep->info.media_type = media_type;
+	sep->codec = codec_type;
+	sep->ind = ind;
+	sep->cfm = cfm;
+	sep->user_data = user_data;
+	sep->delay_reporting = delay_reporting;
+
+	DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
+			sep->info.type, sep->codec, sep->info.seid);
+
+	queue_push_tail(lseps, sep);
+
+	return sep;
+}
+
+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+							uint16_t codec_id)
+{
+	sep->vndcodec_vendor = vendor_id;
+	sep->vndcodec_codec = codec_id;
+}
+
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep)
+{
+	if (!sep)
+		return -EINVAL;
+
+	if (sep->stream)
+		release_stream(sep->stream, sep->stream->session);
+
+	DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep,
+			sep->info.type, sep->codec, sep->info.seid);
+
+	util_clear_uid(&seids, sep->info.seid);
+	queue_remove(lseps, sep);
+	g_free(sep);
+
+	return 0;
+}
+
+const char *avdtp_strerror(struct avdtp_error *err)
+{
+	if (err->category == AVDTP_ERRNO)
+		return strerror(err->err.posix_errno);
+
+	switch (err->err.error_code) {
+	case AVDTP_BAD_HEADER_FORMAT:
+		return "Bad Header Format";
+	case AVDTP_BAD_LENGTH:
+		return "Bad Packet Length";
+	case AVDTP_BAD_ACP_SEID:
+		return "Bad Acceptor SEID";
+	case AVDTP_SEP_IN_USE:
+		return "Stream End Point in Use";
+	case AVDTP_SEP_NOT_IN_USE:
+		return "Stream End Point Not in Use";
+	case AVDTP_BAD_SERV_CATEGORY:
+		return "Bad Service Category";
+	case AVDTP_BAD_PAYLOAD_FORMAT:
+		return "Bad Payload format";
+	case AVDTP_NOT_SUPPORTED_COMMAND:
+		return "Command Not Supported";
+	case AVDTP_INVALID_CAPABILITIES:
+		return "Invalid Capabilities";
+	case AVDTP_BAD_RECOVERY_TYPE:
+		return "Bad Recovery Type";
+	case AVDTP_BAD_MEDIA_TRANSPORT_FORMAT:
+		return "Bad Media Transport Format";
+	case AVDTP_BAD_RECOVERY_FORMAT:
+		return "Bad Recovery Format";
+	case AVDTP_BAD_ROHC_FORMAT:
+		return "Bad Header Compression Format";
+	case AVDTP_BAD_CP_FORMAT:
+		return "Bad Content Protection Format";
+	case AVDTP_BAD_MULTIPLEXING_FORMAT:
+		return "Bad Multiplexing Format";
+	case AVDTP_UNSUPPORTED_CONFIGURATION:
+		return "Configuration not supported";
+	case AVDTP_BAD_STATE:
+		return "Bad State";
+	default:
+		return "Unknown error";
+	}
+}
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
+{
+	return sep->state;
+}
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
+{
+	return g_slist_find(session->streams, stream) ? TRUE : FALSE;
+}
diff --git a/repo/android/avdtp.h b/repo/android/avdtp.h
new file mode 100644
index 0000000..07516a8
--- /dev/null
+++ b/repo/android/avdtp.h
@@ -0,0 +1,291 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+struct avdtp;
+struct avdtp_stream;
+struct avdtp_local_sep;
+struct avdtp_remote_sep;
+struct avdtp_error {
+	uint8_t category;
+	union {
+		uint8_t error_code;
+		int posix_errno;
+	} err;
+};
+
+#define AVDTP_PSM 25
+
+/* SEP capability categories */
+#define AVDTP_MEDIA_TRANSPORT			0x01
+#define AVDTP_REPORTING				0x02
+#define AVDTP_RECOVERY				0x03
+#define AVDTP_CONTENT_PROTECTION		0x04
+#define AVDTP_HEADER_COMPRESSION		0x05
+#define AVDTP_MULTIPLEXING			0x06
+#define AVDTP_MEDIA_CODEC			0x07
+#define AVDTP_DELAY_REPORTING			0x08
+#define AVDTP_ERRNO				0xff
+
+/* AVDTP error definitions */
+#define AVDTP_BAD_HEADER_FORMAT			0x01
+#define AVDTP_BAD_LENGTH			0x11
+#define AVDTP_BAD_ACP_SEID			0x12
+#define AVDTP_SEP_IN_USE			0x13
+#define AVDTP_SEP_NOT_IN_USE			0x14
+#define AVDTP_BAD_SERV_CATEGORY			0x17
+#define AVDTP_BAD_PAYLOAD_FORMAT		0x18
+#define AVDTP_NOT_SUPPORTED_COMMAND		0x19
+#define AVDTP_INVALID_CAPABILITIES		0x1A
+#define AVDTP_BAD_RECOVERY_TYPE			0x22
+#define AVDTP_BAD_MEDIA_TRANSPORT_FORMAT	0x23
+#define AVDTP_BAD_RECOVERY_FORMAT		0x25
+#define AVDTP_BAD_ROHC_FORMAT			0x26
+#define AVDTP_BAD_CP_FORMAT			0x27
+#define AVDTP_BAD_MULTIPLEXING_FORMAT		0x28
+#define AVDTP_UNSUPPORTED_CONFIGURATION		0x29
+#define AVDTP_BAD_STATE				0x31
+
+/* SEP types definitions */
+#define AVDTP_SEP_TYPE_SOURCE			0x00
+#define AVDTP_SEP_TYPE_SINK			0x01
+
+/* Media types definitions */
+#define AVDTP_MEDIA_TYPE_AUDIO			0x00
+#define AVDTP_MEDIA_TYPE_VIDEO			0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA		0x02
+
+typedef enum {
+	AVDTP_STATE_IDLE,
+	AVDTP_STATE_CONFIGURED,
+	AVDTP_STATE_OPEN,
+	AVDTP_STATE_STREAMING,
+	AVDTP_STATE_CLOSING,
+	AVDTP_STATE_ABORTING,
+} avdtp_state_t;
+
+struct avdtp_service_capability {
+	uint8_t category;
+	uint8_t length;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_media_codec_capability {
+	uint8_t rfa0:4;
+	uint8_t media_type:4;
+	uint8_t media_codec_type;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_media_codec_capability {
+	uint8_t media_type:4;
+	uint8_t rfa0:4;
+	uint8_t media_codec_type;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+typedef void (*avdtp_stream_state_cb) (struct avdtp_stream *stream,
+					avdtp_state_t old_state,
+					avdtp_state_t new_state,
+					struct avdtp_error *err,
+					void *user_data);
+
+typedef void (*avdtp_set_configuration_cb) (struct avdtp *session,
+						struct avdtp_stream *stream,
+						struct avdtp_error *err);
+
+/* Callbacks for when a reply is received to a command that we sent */
+struct avdtp_sep_cfm {
+	void (*set_configuration) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data);
+	void (*get_configuration) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data);
+	void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data);
+	void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data);
+	void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
+	void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
+	void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
+	void (*reconfigure) (struct avdtp *session,
+				struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
+	void (*delay_report) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
+};
+
+/*
+ * Callbacks for indicating when we received a new command. The return value
+ * indicates whether the command should be rejected or accepted
+ */
+struct avdtp_sep_ind {
+	gboolean (*get_capability) (struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					GSList **caps, uint8_t *err,
+					void *user_data);
+	gboolean (*set_configuration) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					GSList *caps,
+					avdtp_set_configuration_cb cb,
+					void *user_data);
+	gboolean (*get_configuration) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					uint8_t *err, void *user_data);
+	gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data);
+	gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data);
+	gboolean (*suspend) (struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data);
+	gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data);
+	void (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data);
+	gboolean (*reconfigure) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					uint8_t *err, void *user_data);
+	gboolean (*delayreport) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					uint8_t rseid, uint16_t delay,
+					uint8_t *err, void *user_data);
+};
+
+typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
+					struct avdtp_error *err, void *user_data);
+typedef void (*avdtp_disconnect_cb_t) (void *user_data);
+
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+							struct queue *lseps);
+
+unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
+						avdtp_disconnect_cb_t cb,
+						void *user_data);
+gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id);
+
+void avdtp_shutdown(struct avdtp *session);
+
+void avdtp_unref(struct avdtp *session);
+struct avdtp *avdtp_ref(struct avdtp *session);
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+							const void *data,
+							int size);
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+			void *user_data);
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream);
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+					struct avdtp_stream *stream,
+					avdtp_stream_state_cb cb, void *data);
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+				struct avdtp_stream *stream,
+				unsigned int id);
+
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+						size_t imtu, size_t omtu);
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+					uint16_t *imtu, uint16_t *omtu,
+					GSList **caps);
+struct avdtp_service_capability *avdtp_stream_get_codec(
+						struct avdtp_stream *stream);
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+					GSList *caps);
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+						struct avdtp_stream *stream);
+
+int avdtp_set_configuration(struct avdtp *session,
+				struct avdtp_remote_sep *rsep,
+				struct avdtp_local_sep *lsep,
+				GSList *caps,
+				struct avdtp_stream **stream);
+
+int avdtp_get_configuration(struct avdtp *session,
+				struct avdtp_stream *stream);
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+		gboolean immediate);
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+							uint16_t delay);
+
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+						uint8_t media_type,
+						uint8_t codec_type,
+						gboolean delay_reporting,
+						struct avdtp_sep_ind *ind,
+						struct avdtp_sep_cfm *cfm,
+						void *user_data);
+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+							uint16_t codec_id);
+
+/* Find a matching pair of local and remote SEP ID's */
+struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
+						struct avdtp_local_sep *lsep);
+
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id);
+const char *avdtp_strerror(struct avdtp_error *err);
+uint8_t avdtp_error_category(struct avdtp_error *err);
+int avdtp_error_error_code(struct avdtp_error *err);
+int avdtp_error_posix_errno(struct avdtp_error *err);
diff --git a/repo/android/avdtptest.c b/repo/android/avdtptest.c
new file mode 100644
index 0000000..ce34443
--- /dev/null
+++ b/repo/android/avdtptest.c
@@ -0,0 +1,909 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *
+ *
+ *  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 <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
+#include "btio/btio.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "avdtp.h"
+
+static GMainLoop *mainloop = NULL;
+static int dev_role = AVDTP_SEP_TYPE_SOURCE;
+static bool preconf = false;
+static struct avdtp *avdtp = NULL;
+struct avdtp_stream *avdtp_stream = NULL;
+struct avdtp_local_sep *local_sep = NULL;
+struct avdtp_remote_sep *remote_sep = NULL;
+static GIOChannel *io = NULL;
+static bool reject = false;
+static bdaddr_t src;
+static bdaddr_t dst;
+static uint16_t version = 0x0103;
+static guint media_player = 0;
+static guint media_recorder = 0;
+static guint idle_id = 0;
+static struct queue *lseps = NULL;
+
+static bool fragment = false;
+
+static enum {
+	CMD_GET_CONF,
+	CMD_OPEN,
+	CMD_START,
+	CMD_SUSPEND,
+	CMD_CLOSE,
+	CMD_ABORT,
+	CMD_DELAY,
+	CMD_NONE,
+} command = CMD_NONE;
+
+static const char sbc_codec[] = {0x00, 0x00, 0x11, 0x15, 0x02, 0x40};
+static const char sbc_media_frame[] = {
+	0x00, 0x60, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+	0x01, 0x9c, 0xfd, 0x40, 0xbd, 0xde, 0xa9, 0x75, 0x43, 0x20, 0x87, 0x64,
+	0x44, 0x32, 0x7f, 0xbe, 0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x7f, 0xbe,
+	0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x7f, 0xbe, 0xf7, 0x76, 0xfe, 0xf7,
+	0xbb, 0xbb, 0x80, 0x3e, 0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x83, 0x41,
+	0x07, 0x77, 0x09, 0x07, 0x43, 0xb3, 0x81, 0xbc, 0xf8, 0x77, 0x02, 0xe5,
+	0xa4, 0x3a, 0xa0, 0xcb, 0x38, 0xbb, 0x57, 0x90, 0xd9, 0x08, 0x9c, 0x1d,
+	0x86, 0x59, 0x01, 0x0c, 0x21, 0x44, 0x68, 0x35, 0xa8, 0x57, 0x97, 0x0e,
+	0x9b, 0xbb, 0x62, 0xc4, 0xca, 0x57, 0x04, 0xa1, 0xca, 0x3b, 0xa3, 0x48,
+	0xd2, 0x66, 0x11, 0x33, 0x6a, 0x3b, 0xb4, 0xbb, 0x08, 0x77, 0x17, 0x03,
+	0xb4, 0x3b, 0x79, 0x3b, 0x46, 0x97, 0x0e, 0xf7, 0x3d, 0xbb, 0x3d, 0x49,
+	0x25, 0x86, 0x88, 0xb4, 0xad, 0x3b, 0x62, 0xbb, 0xa4, 0x47, 0x29, 0x99,
+	0x3b, 0x3b, 0xaf, 0xc6, 0xd4, 0x37, 0x68, 0x94, 0x0a, 0xbb
+	};
+
+static void parse_command(const char *cmd)
+{
+	if (!strncmp(cmd, "getconf", sizeof("getconf"))) {
+		command = CMD_GET_CONF;
+	} else if (!strncmp(cmd, "open", sizeof("open"))) {
+		command = CMD_OPEN;
+	} else if (!strncmp(cmd, "start", sizeof("start"))) {
+		command = CMD_START;
+	} else if (!strncmp(cmd, "suspend", sizeof("suspend"))) {
+		command = CMD_SUSPEND;
+	} else if (!strncmp(cmd, "close", sizeof("close"))) {
+		command = CMD_CLOSE;
+	} else if (!strncmp(cmd, "abort", sizeof("abort"))) {
+		command = CMD_ABORT;
+	} else if (!strncmp(cmd, "delay", sizeof("delay"))) {
+		command = CMD_DELAY;
+	} else {
+		printf("Unknown command '%s'\n", cmd);
+		printf("(getconf open start suspend close abort delay)\n");
+		exit(1);
+	}
+}
+
+static void send_command(void)
+{
+	avdtp_state_t state = avdtp_sep_get_state(local_sep);
+
+	switch (command) {
+	case CMD_GET_CONF:
+		avdtp_get_configuration(avdtp, avdtp_stream);
+		break;
+	case CMD_OPEN:
+		if (state == AVDTP_STATE_CONFIGURED)
+			avdtp_open(avdtp, avdtp_stream);
+		break;
+	case CMD_START:
+		if (state == AVDTP_STATE_OPEN)
+			avdtp_start(avdtp, avdtp_stream);
+		break;
+	case CMD_SUSPEND:
+		if (state == AVDTP_STATE_STREAMING)
+			avdtp_suspend(avdtp , avdtp_stream);
+		break;
+	case CMD_CLOSE:
+		if (state == AVDTP_STATE_STREAMING)
+			avdtp_close(avdtp, avdtp_stream, FALSE);
+		break;
+	case CMD_ABORT:
+		avdtp_abort(avdtp , avdtp_stream);
+		break;
+	case CMD_DELAY:
+		avdtp_delay_report(avdtp , avdtp_stream , 250);
+		break;
+	case CMD_NONE:
+	default:
+		break;
+	}
+}
+
+static gboolean media_writer(gpointer user_data)
+{
+	uint16_t omtu;
+	int fd;
+	int to_write;
+
+	if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+		return TRUE;
+
+	if (omtu < sizeof(sbc_media_frame))
+		to_write = omtu;
+	else
+		to_write = sizeof(sbc_media_frame);
+
+	if (write(fd, sbc_media_frame, to_write) < 0)
+		return TRUE;
+
+	send_command();
+
+	return TRUE;
+}
+
+static bool start_media_player(void)
+{
+	int fd;
+	uint16_t omtu;
+
+	printf("Media streaming started\n");
+
+	if (media_player || !avdtp_stream)
+		return false;
+
+	if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+		return false;
+
+	media_player = g_timeout_add(200, media_writer, NULL);
+	if (!media_player)
+		return false;
+
+	return true;
+}
+
+static void stop_media_player(void)
+{
+	if (!media_player)
+		return;
+
+	printf("Media streaming stopped\n");
+
+	g_source_remove(media_player);
+	media_player = 0;
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+	unsigned cc:4;
+	unsigned x:1;
+	unsigned p:1;
+	unsigned v:2;
+
+	unsigned pt:7;
+	unsigned m:1;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	uint32_t csrc[0];
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_header {
+	unsigned v:2;
+	unsigned p:1;
+	unsigned x:1;
+	unsigned cc:4;
+
+	unsigned m:1;
+	unsigned pt:7;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	uint32_t csrc[0];
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+static gboolean media_reader(GIOChannel *source, GIOCondition condition,
+								gpointer data)
+{
+	char buf[UINT16_MAX];
+	struct rtp_header *rtp = (void *) buf;
+	static bool decode = false;
+	uint16_t imtu;
+	int fd, ret;
+
+	if (!avdtp_stream_get_transport(avdtp_stream, &fd, &imtu, NULL, NULL))
+		return TRUE;
+
+	ret = read(fd, buf, imtu);
+	if (ret < 0) {
+		printf("Reading failed (%s)\n", strerror(errno));
+		return TRUE;
+	}
+
+	if (ret < (int) sizeof(*rtp)) {
+		printf("Not enough media data received (%u bytes)", ret);
+		return TRUE;
+	}
+
+	if (!decode) {
+		printf("V=%u P=%u X=%u CC=%u M=%u PT=%u SeqNr=%d\n",
+			rtp->v, rtp->p, rtp->x, rtp->cc, rtp->m, rtp->pt,
+			be16_to_cpu(rtp->sequence_number));
+		decode = true;
+	}
+
+	send_command();
+
+	return TRUE;
+}
+
+static bool start_media_recorder(void)
+{
+	int fd;
+	uint16_t omtu;
+	GIOChannel *chan;
+
+	printf("Media recording started\n");
+
+	if (media_recorder || !avdtp_stream)
+		return false;
+
+	if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+		return false;
+
+	chan = g_io_channel_unix_new(fd);
+
+	media_recorder = g_io_add_watch(chan, G_IO_IN, media_reader, NULL);
+	g_io_channel_unref(chan);
+
+	if (!media_recorder)
+		return false;
+
+	return true;
+}
+
+static void stop_media_recorder(void)
+{
+	if (!media_recorder)
+		return;
+
+	printf("Media recording stopped\n");
+
+	g_source_remove(media_recorder);
+	media_recorder = 0;
+}
+
+static void set_configuration_cfm(struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (preconf)
+		avdtp_open(avdtp, avdtp_stream);
+}
+
+static void get_configuration_cfm(struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data)
+	{
+	printf("%s\n", __func__);
+}
+
+static void disconnect_cb(void *user_data)
+{
+	printf("Disconnected\n");
+
+	g_main_loop_quit(mainloop);
+}
+
+static void discover_cb(struct avdtp *session, GSList *seps,
+				struct avdtp_error *err, void *user_data)
+{
+	struct avdtp_service_capability *service;
+	GSList *caps = NULL;
+	int ret;
+
+	remote_sep = avdtp_find_remote_sep(avdtp, local_sep);
+	if (!remote_sep) {
+		printf("Unable to find matching endpoint\n");
+		avdtp_shutdown(session);
+		return;
+	}
+
+	printf("Matching endpoint found\n");
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+	caps = g_slist_append(caps, service);
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, sbc_codec,
+							sizeof(sbc_codec));
+	caps = g_slist_append(caps, service);
+
+	ret = avdtp_set_configuration(avdtp, remote_sep, local_sep, caps,
+								&avdtp_stream);
+
+	g_slist_free_full(caps, g_free);
+
+	if (ret < 0) {
+		printf("Failed to set configuration (%s)\n", strerror(-ret));
+		avdtp_shutdown(session);
+	}
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	uint16_t imtu, omtu;
+	GError *gerr = NULL;
+	int fd;
+
+	if (err) {
+		printf("%s\n", err->message);
+		g_main_loop_quit(mainloop);
+		return;
+	}
+
+	bt_io_get(chan, &gerr,
+			BT_IO_OPT_IMTU, &imtu,
+			BT_IO_OPT_OMTU, &omtu,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_INVALID);
+	if (gerr) {
+		printf("%s\n", gerr->message);
+		g_main_loop_quit(mainloop);
+		return;
+	}
+
+	printf("Connected (imtu=%d omtu=%d)\n", imtu, omtu);
+
+	fd = g_io_channel_unix_get_fd(chan);
+
+	if (avdtp && avdtp_stream) {
+		if (!avdtp_stream_set_transport(avdtp_stream, fd, imtu, omtu)) {
+			printf("avdtp_stream_set_transport: failed\n");
+			g_main_loop_quit(mainloop);
+		}
+
+		g_io_channel_set_close_on_unref(chan, FALSE);
+
+		send_command();
+
+		return;
+	}
+
+	avdtp = avdtp_new(fd, imtu, omtu, version, lseps);
+	if (!avdtp) {
+		printf("Failed to create avdtp instance\n");
+		g_main_loop_quit(mainloop);
+		return;
+	}
+
+	avdtp_add_disconnect_cb(avdtp, disconnect_cb, NULL);
+
+	if (preconf) {
+		int ret;
+
+		ret = avdtp_discover(avdtp, discover_cb, NULL);
+		if (ret < 0) {
+			printf("avdtp_discover failed: %s", strerror(-ret));
+			g_main_loop_quit(mainloop);
+		}
+	}
+}
+
+static GIOChannel *do_connect(GError **err)
+{
+	if (fragment)
+		return bt_io_connect(connect_cb, NULL, NULL, err,
+					BT_IO_OPT_SOURCE_BDADDR, &src,
+					BT_IO_OPT_DEST_BDADDR, &dst,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+					BT_IO_OPT_PSM, AVDTP_PSM,
+					BT_IO_OPT_MTU, 48,
+					BT_IO_OPT_INVALID);
+
+	return bt_io_connect(connect_cb, NULL, NULL, err,
+				BT_IO_OPT_SOURCE_BDADDR, &src,
+				BT_IO_OPT_DEST_BDADDR, &dst,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_PSM, AVDTP_PSM,
+				BT_IO_OPT_INVALID);
+}
+
+static void open_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	GError *gerr = NULL;
+
+	printf("%s\n", __func__);
+
+	do_connect(&gerr);
+	if (gerr) {
+		printf("connect failed: %s\n", gerr->message);
+		g_error_free(gerr);
+		g_main_loop_quit(mainloop);
+	}
+}
+
+static void start_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		start_media_player();
+	else
+		start_media_recorder();
+}
+
+static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream,
+			struct avdtp_error *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+}
+
+static void close_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream,
+			struct avdtp_error *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+
+	avdtp_stream = NULL;
+}
+
+static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+			struct avdtp_stream *stream,
+			struct avdtp_error *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+
+	avdtp_stream = NULL;
+}
+
+static void reconfigure_cfm(struct avdtp *session,
+				struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	printf("%s\n", __func__);
+}
+
+static void delay_report_cfm(struct avdtp *session,
+				struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	printf("%s\n", __func__);
+}
+
+static struct avdtp_sep_cfm sep_cfm = {
+	.set_configuration	= set_configuration_cfm,
+	.get_configuration	= get_configuration_cfm,
+	.open			= open_cfm,
+	.start			= start_cfm,
+	.suspend		= suspend_cfm,
+	.close			= close_cfm,
+	.abort			= abort_cfm,
+	.reconfigure		= reconfigure_cfm,
+	.delay_report		= delay_report_cfm,
+};
+
+static gboolean get_capability_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					GSList **caps, uint8_t *err,
+					void *user_data)
+{
+	struct avdtp_service_capability *service;
+	int i;
+
+	printf("%s\n", __func__);
+
+	if (idle_id > 0) {
+		g_source_remove(idle_id);
+		idle_id = 0;
+	}
+
+	if (reject)
+		return FALSE;
+
+	*caps = NULL;
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+	*caps = g_slist_append(*caps, service);
+
+	service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, sbc_codec,
+						sizeof(sbc_codec));
+	*caps = g_slist_append(*caps, service);
+
+	if (fragment)
+		for (i = 0; i < 10; i++) {
+			service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC,
+							sbc_codec,
+							sizeof(sbc_codec));
+			*caps = g_slist_append(*caps, service);
+		}
+
+	return TRUE;
+}
+
+static gboolean set_configuration_ind(struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					struct avdtp_stream *stream,
+					GSList *caps,
+					avdtp_set_configuration_cb cb,
+					void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	if (idle_id > 0) {
+		g_source_remove(idle_id);
+		idle_id = 0;
+	}
+
+	avdtp_stream = stream;
+
+	cb(session, stream, NULL);
+
+	send_command();
+
+	return TRUE;
+}
+
+static gboolean get_configuration_ind(struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					uint8_t *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	send_command();
+
+	return TRUE;
+}
+
+static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		start_media_player();
+	else
+		start_media_recorder();
+
+	send_command();
+
+	return TRUE;
+}
+
+static gboolean suspend_ind(struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+
+	return TRUE;
+}
+
+static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+
+	avdtp_stream = NULL;
+
+	return TRUE;
+}
+
+static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, uint8_t *err,
+			void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+		stop_media_player();
+	else
+		stop_media_recorder();
+
+	avdtp_stream = NULL;
+}
+
+static gboolean reconfigure_ind(struct avdtp *session,
+				struct avdtp_local_sep *lsep,
+				uint8_t *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean delayreport_ind(struct avdtp *session,
+				struct avdtp_local_sep *lsep,
+				uint8_t rseid, uint16_t delay,
+				uint8_t *err, void *user_data)
+{
+	printf("%s\n", __func__);
+
+	if (reject)
+		return FALSE;
+
+	return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+	.get_capability		= get_capability_ind,
+	.set_configuration	= set_configuration_ind,
+	.get_configuration	= get_configuration_ind,
+	.open			= open_ind,
+	.close			= close_ind,
+	.start			= start_ind,
+	.suspend		= suspend_ind,
+	.abort			= abort_ind,
+	.reconfigure		= reconfigure_ind,
+	.delayreport		= delayreport_ind,
+};
+
+static void usage(void)
+{
+	printf("avdtptest - AVDTP testing ver %s\n", VERSION);
+	printf("Usage:\n"
+		"\tavdtptest [options]\n");
+	printf("options:\n"
+		"\t-d <device_role>   SRC (source) or SINK (sink)\n"
+		"\t-i <hcidev>        HCI adapter\n"
+		"\t-c <bdaddr>        connect\n"
+		"\t-l                 listen\n"
+		"\t-r                 reject commands\n"
+		"\t-f                 fragment\n"
+		"\t-p                 configure stream\n"
+		"\t-s <command>       send command\n"
+		"\t-v <version>       set version (0x0100, 0x0102, 0x0103\n");
+}
+
+static struct option main_options[] = {
+	{ "help",		0, 0, 'h' },
+	{ "device_role",	1, 0, 'd' },
+	{ "adapter",		1, 0, 'i' },
+	{ "connect",		1, 0, 'c' },
+	{ "listen",		0, 0, 'l' },
+	{ "reject",		0, 0, 'r' },
+	{ "fragment",		0, 0, 'f' },
+	{ "preconf",		0, 0, 'p' },
+	{ "send",		1, 0, 's' },
+	{ "version",		1, 0, 'v' },
+	{ 0, 0, 0, 0 }
+};
+
+static GIOChannel *do_listen(GError **err)
+{
+	if (fragment)
+		return bt_io_listen(connect_cb, NULL, NULL, NULL, err,
+					BT_IO_OPT_SOURCE_BDADDR, &src,
+					BT_IO_OPT_PSM, AVDTP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+					BT_IO_OPT_MTU, 48,
+					BT_IO_OPT_INVALID);
+
+	return bt_io_listen(connect_cb, NULL, NULL, NULL, err,
+					BT_IO_OPT_SOURCE_BDADDR, &src,
+					BT_IO_OPT_PSM, AVDTP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+					BT_IO_OPT_INVALID);
+}
+
+int main(int argc, char *argv[])
+{
+	GError *err = NULL;
+	int opt;
+
+	bacpy(&src, BDADDR_ANY);
+	bacpy(&dst, BDADDR_ANY);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+	if (!mainloop) {
+		printf("Failed to create main loop\n");
+
+		exit(1);
+	}
+
+	while ((opt = getopt_long(argc, argv, "d:hi:s:c:v:lrfp",
+						main_options, NULL)) != EOF) {
+		switch (opt) {
+		case 'i':
+			if (!strncmp(optarg, "hci", 3))
+				hci_devba(atoi(optarg + 3), &src);
+			else
+				str2ba(optarg, &src);
+			break;
+		case 'd':
+			if (!strncasecmp(optarg, "SRC", sizeof("SRC"))) {
+				dev_role = AVDTP_SEP_TYPE_SOURCE;
+			} else if (!strncasecmp(optarg, "SINK",
+							sizeof("SINK"))) {
+				dev_role = AVDTP_SEP_TYPE_SINK;
+			} else {
+				usage();
+				exit(1);
+			}
+			break;
+		case 'c':
+			if (str2ba(optarg, &dst) < 0) {
+				usage();
+				exit(1);
+			}
+			break;
+		case 'l':
+			bacpy(&dst, BDADDR_ANY);
+			break;
+		case 'r':
+			reject = true;
+			break;
+		case 'f':
+			fragment = true;
+			break;
+		case 'p':
+			preconf = true;
+			break;
+		case 's':
+			parse_command(optarg);
+			break;
+		case 'v':
+			version = strtol(optarg, NULL, 0);
+			if (version != 0x0100 && version != 0x0102 &&
+							version != 0x0103) {
+				printf("invalid version\n");
+				exit(1);
+			}
+
+			break;
+		case 'h':
+			usage();
+			exit(0);
+		default:
+			usage();
+			exit(1);
+		}
+	}
+
+	lseps = queue_new();
+
+	local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
+					0x00, TRUE, &sep_ind, &sep_cfm, NULL);
+	if (!local_sep) {
+		printf("Failed to register sep\n");
+		exit(1);
+	}
+
+	queue_push_tail(lseps, local_sep);
+
+	if (!bacmp(&dst, BDADDR_ANY)) {
+		printf("Listening...\n");
+		io = do_listen(&err);
+	} else {
+		printf("Connecting...\n");
+		io = do_connect(&err);
+	}
+
+	if (!io) {
+		printf("Failed: %s\n", err->message);
+		g_error_free(err);
+		exit(1);
+	}
+
+	g_main_loop_run(mainloop);
+
+	printf("Done\n");
+
+	queue_destroy(lseps, NULL);
+
+	avdtp_unref(avdtp);
+	avdtp = NULL;
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	return 0;
+}
diff --git a/repo/android/avrcp-lib.c b/repo/android/avrcp-lib.c
new file mode 100644
index 0000000..4edfd0e
--- /dev/null
+++ b/repo/android/avrcp-lib.c
@@ -0,0 +1,3615 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+
+/* Packet types */
+#define AVRCP_PACKET_TYPE_SINGLE		0x00
+#define AVRCP_PACKET_TYPE_START			0x01
+#define AVRCP_PACKET_TYPE_CONTINUING		0x02
+#define AVRCP_PACKET_TYPE_END			0x03
+
+#define AVRCP_CHARSET_UTF8	0x006a
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+	uint8_t company_id[3];
+	uint8_t pdu_id;
+	uint8_t packet_type:2;
+	uint8_t rsvd:6;
+	uint16_t params_len;
+	uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+	uint8_t company_id[3];
+	uint8_t pdu_id;
+	uint8_t rsvd:6;
+	uint8_t packet_type:2;
+	uint16_t params_len;
+	uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avrcp_browsing_header {
+	uint8_t pdu_id;
+	uint16_t params_len;
+	uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
+struct get_capabilities_req {
+	uint8_t cap;
+	uint8_t params[0];
+} __attribute__ ((packed));
+
+struct get_capabilities_rsp {
+	uint8_t cap;
+	uint8_t number;
+	uint8_t params[0];
+} __attribute__ ((packed));
+
+struct list_attributes_rsp {
+	uint8_t number;
+	uint8_t params[0];
+} __attribute__ ((packed));
+
+struct list_values_req {
+	uint8_t attr;
+} __attribute__ ((packed));
+
+struct list_values_rsp {
+	uint8_t number;
+	uint8_t params[0];
+} __attribute__ ((packed));
+
+struct get_value_req {
+	uint8_t number;
+	uint8_t attrs[0];
+} __attribute__ ((packed));
+
+struct attr_value {
+	uint8_t attr;
+	uint8_t value;
+} __attribute__ ((packed));
+
+struct value_rsp {
+	uint8_t number;
+	struct attr_value values[0];
+} __attribute__ ((packed));
+
+struct set_value_req {
+	uint8_t number;
+	struct attr_value values[0];
+} __attribute__ ((packed));
+
+struct get_attribute_text_req {
+	uint8_t number;
+	uint8_t attrs[0];
+} __attribute__ ((packed));
+
+struct text_value {
+	uint8_t attr;
+	uint16_t charset;
+	uint8_t len;
+	char data[0];
+} __attribute__ ((packed));
+
+struct get_attribute_text_rsp {
+	uint8_t number;
+	struct text_value values[0];
+} __attribute__ ((packed));
+
+struct get_value_text_req {
+	uint8_t attr;
+	uint8_t number;
+	uint8_t values[0];
+} __attribute__ ((packed));
+
+struct get_value_text_rsp {
+	uint8_t number;
+	struct text_value values[0];
+} __attribute__ ((packed));
+
+struct media_item {
+	uint32_t attr;
+	uint16_t charset;
+	uint16_t len;
+	char data[0];
+} __attribute__ ((packed));
+
+struct get_element_attributes_req {
+	uint64_t id;
+	uint8_t number;
+	uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_element_attributes_rsp {
+	uint8_t number;
+	struct media_item items[0];
+} __attribute__ ((packed));
+
+struct get_play_status_rsp {
+	uint32_t duration;
+	uint32_t position;
+	uint8_t status;
+} __attribute__ ((packed));
+
+struct register_notification_req {
+	uint8_t event;
+	uint32_t interval;
+} __attribute__ ((packed));
+
+struct register_notification_rsp {
+	uint8_t event;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct set_volume_req {
+	uint8_t value;
+} __attribute__ ((packed));
+
+struct set_volume_rsp {
+	uint8_t value;
+} __attribute__ ((packed));
+
+struct set_addressed_req {
+	uint16_t id;
+} __attribute__ ((packed));
+
+struct set_addressed_rsp {
+	uint8_t status;
+} __attribute__ ((packed));
+
+struct set_browsed_req {
+	uint16_t id;
+} __attribute__ ((packed));
+
+struct set_browsed_rsp {
+	uint8_t status;
+	uint16_t counter;
+	uint32_t items;
+	uint16_t charset;
+	uint8_t depth;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct get_folder_items_req {
+	uint8_t scope;
+	uint32_t start;
+	uint32_t end;
+	uint8_t number;
+	uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_folder_items_rsp {
+	uint8_t status;
+	uint16_t counter;
+	uint16_t number;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct change_path_req {
+	uint16_t counter;
+	uint8_t direction;
+	uint64_t uid;
+} __attribute__ ((packed));
+
+struct change_path_rsp {
+	uint8_t status;
+	uint32_t items;
+} __attribute__ ((packed));
+
+struct get_item_attributes_req {
+	uint8_t scope;
+	uint64_t uid;
+	uint16_t counter;
+	uint8_t number;
+	uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_item_attributes_rsp {
+	uint8_t status;
+	uint8_t number;
+	struct media_item items[0];
+} __attribute__ ((packed));
+
+struct play_item_req {
+	uint8_t scope;
+	uint64_t uid;
+	uint16_t counter;
+} __attribute__ ((packed));
+
+struct play_item_rsp {
+	uint8_t status;
+} __attribute__ ((packed));
+
+struct search_req {
+	uint16_t charset;
+	uint16_t len;
+	char string[0];
+} __attribute__ ((packed));
+
+struct search_rsp {
+	uint8_t status;
+	uint16_t counter;
+	uint32_t items;
+} __attribute__ ((packed));
+
+struct add_to_now_playing_req {
+	uint8_t scope;
+	uint64_t uid;
+	uint16_t counter;
+} __attribute__ ((packed));
+
+struct add_to_now_playing_rsp {
+	uint8_t status;
+} __attribute__ ((packed));
+
+struct avrcp_control_handler {
+	uint8_t id;
+	uint8_t code;
+	uint8_t rsp;
+	ssize_t (*func) (struct avrcp *session, uint8_t transaction,
+			uint16_t params_len, uint8_t *params, void *user_data);
+};
+
+struct avrcp_browsing_handler {
+	uint8_t id;
+	ssize_t (*func) (struct avrcp *session, uint8_t transaction,
+			uint16_t params_len, uint8_t *params, void *user_data);
+};
+
+struct avrcp_continuing {
+	uint8_t pdu_id;
+	struct iovec pdu;
+};
+
+struct avrcp {
+	struct avctp *conn;
+	struct avrcp_player *player;
+
+	const struct avrcp_control_handler *control_handlers;
+	void *control_data;
+	unsigned int control_id;
+	uint16_t control_mtu;
+
+	struct avrcp_continuing *continuing;
+
+	const struct avrcp_passthrough_handler *passthrough_handlers;
+	void *passthrough_data;
+	unsigned int passthrough_id;
+
+	const struct avrcp_browsing_handler *browsing_handlers;
+	void *browsing_data;
+	unsigned int browsing_id;
+
+	avrcp_destroy_cb_t destroy;
+	void *destroy_data;
+};
+
+struct avrcp_player {
+	const struct avrcp_control_ind *ind;
+	const struct avrcp_control_cfm *cfm;
+
+	void *user_data;
+};
+
+static inline uint32_t ntoh24(const uint8_t src[3])
+{
+	return src[0] << 16 | src[1] << 8 | src[2];
+}
+
+static inline void hton24(uint8_t dst[3], uint32_t src)
+{
+	dst[0] = (src & 0xff0000) >> 16;
+	dst[1] = (src & 0x00ff00) >> 8;
+	dst[2] = (src & 0x0000ff);
+}
+