Blame SOURCES/0001-Add-sixaxis-cable-pairing-plugin.patch

19062e
From 64f9449656dbbb718d53a54ed8e7904e289280ec Mon Sep 17 00:00:00 2001
19062e
From: Bastien Nocera <hadess@hadess.net>
19062e
Date: Fri, 30 Dec 2011 12:34:29 +0100
19062e
Subject: [PATCH] Add sixaxis cable-pairing plugin
19062e
19062e
Implement the old "sixpair" using libudev and libusb-1.0.
19062e
19062e
When a Sixaxis device is plugged in, events are filtered, and
19062e
the device is selected, poked around to set the default Bluetooth
19062e
address, and added to the database of the current default adapter.
19062e
---
19062e
 Makefile.am     |    9 +-
19062e
 acinclude.m4    |   16 +++
19062e
 configure.ac    |    1 +
19062e
 plugins/cable.c |  382 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
19062e
 src/adapter.c   |   19 +++
19062e
 src/adapter.h   |    3 +
19062e
 6 files changed, 428 insertions(+), 2 deletions(-)
19062e
 create mode 100644 plugins/cable.c
19062e
19062e
diff --git a/Makefile.am b/Makefile.am
19062e
index 53fcbe9..f831a72 100644
19062e
--- a/Makefile.am
19062e
+++ b/Makefile.am
19062e
@@ -238,6 +238,11 @@ builtin_sources += thermometer/main.c \
19062e
 endif
19062e
 
19062e
 
19062e
+if CABLE
19062e
+builtin_modules += cable
19062e
+builtin_sources += plugins/cable.c
19062e
+endif
19062e
+
19062e
 builtin_modules += hciops mgmtops
19062e
 builtin_sources += plugins/hciops.c plugins/mgmtops.c
19062e
 
19062e
@@ -306,7 +311,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
19062e
 			src/event.h src/event.c \
19062e
 			src/oob.h src/oob.c src/eir.h src/eir.c
19062e
 src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
19062e
-								-ldl -lrt
19062e
+								@CABLE_LIBS@ -ldl -lrt
19062e
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
19062e
 				-Wl,--version-script=$(srcdir)/src/bluetooth.ver
19062e
 
19062e
@@ -428,7 +433,7 @@ EXTRA_DIST += doc/manager-api.txt \
19062e
 
19062e
 AM_YFLAGS = -d
19062e
 
19062e
-AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
19062e
+AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CABLE_CFLAGS@
19062e
 
19062e
 INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
19062e
 			-I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus \
19062e
diff --git a/acinclude.m4 b/acinclude.m4
19062e
index 6505ad3..3f59989 100644
19062e
--- a/acinclude.m4
19062e
+++ b/acinclude.m4
19062e
@@ -139,6 +139,12 @@ AC_DEFUN([AC_PATH_UDEV], [
19062e
 	AC_SUBST(UDEV_LIBS)
19062e
 ])
19062e
 
19062e
+AC_DEFUN([AC_PATH_CABLE], [
19062e
+	PKG_CHECK_MODULES(CABLE, libudev libusb-1.0, cable_found=yes, cable_found=no)
19062e
+	AC_SUBST(CABLE_CFLAGS)
19062e
+	AC_SUBST(CABLE_LIBS)
19062e
+])
19062e
+
19062e
 AC_DEFUN([AC_PATH_SNDFILE], [
19062e
 	PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
19062e
 	AC_SUBST(SNDFILE_CFLAGS)
19062e
@@ -176,6 +182,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
19062e
 	sndfile_enable=${sndfile_found}
19062e
 	hal_enable=no
19062e
 	usb_enable=${usb_found}
19062e
+	cable_enable=${cable_found}
19062e
 	alsa_enable=${alsa_found}
19062e
 	gstreamer_enable=${gstreamer_found}
19062e
 	audio_enable=yes
19062e
@@ -265,6 +272,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
19062e
 		usb_enable=${enableval}
19062e
 	])
19062e
 
19062e
+	AC_ARG_ENABLE(cable, AC_HELP_STRING([--enable-cable], [enable DeviceKit support]), [
19062e
+		cable_enable=${enableval}
19062e
+	])
19062e
+
19062e
 	AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
19062e
 		tools_enable=${enableval}
19062e
 	])
19062e
@@ -366,6 +377,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
19062e
 		AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
19062e
 	fi
19062e
 
19062e
+	if (test "${cable_enable}" = "yes" && test "${cable_found}" = "yes"); then
19062e
+		AC_DEFINE(HAVE_CABLE, 1, [Define to 1 if you have libcable.])
19062e
+	fi
19062e
+
19062e
 	AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes")
19062e
 	AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes")
19062e
 	AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" ||
19062e
@@ -398,4 +413,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
19062e
 	AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
19062e
 	AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
19062e
 	AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
19062e
+	AM_CONDITIONAL(CABLE, test "${cable_enable}" = "yes" && test "${cable_found}" = "yes")
19062e
 ])
19062e
diff --git a/configure.ac b/configure.ac
19062e
index 48b181e..45a4b15 100644
19062e
--- a/configure.ac
19062e
+++ b/configure.ac
19062e
@@ -46,6 +46,7 @@ AC_PATH_GSTREAMER
19062e
 AC_PATH_USB
19062e
 AC_PATH_UDEV
19062e
 AC_PATH_SNDFILE
19062e
+AC_PATH_CABLE
19062e
 AC_PATH_OUI
19062e
 AC_PATH_READLINE
19062e
 AC_PATH_CHECK
19062e
diff --git a/plugins/cable.c b/plugins/cable.c
19062e
new file mode 100644
19062e
index 0000000..fe758db
19062e
--- /dev/null
19062e
+++ b/plugins/cable.c
19062e
@@ -0,0 +1,382 @@
19062e
+/*
19062e
+ *
19062e
+ *  BlueZ - Bluetooth protocol stack for Linux
19062e
+ *
19062e
+ *  Copyright (C) 2009  Bastien Nocera <hadess@hadess.net>
19062e
+ *
19062e
+ *
19062e
+ *  This program is free software; you can redistribute it and/or modify
19062e
+ *  it under the terms of the GNU General Public License as published by
19062e
+ *  the Free Software Foundation; either version 2 of the License, or
19062e
+ *  (at your option) any later version.
19062e
+ *
19062e
+ *  This program is distributed in the hope that it will be useful,
19062e
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19062e
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19062e
+ *  GNU General Public License for more details.
19062e
+ *
19062e
+ *  You should have received a copy of the GNU General Public License
19062e
+ *  along with this program; if not, write to the Free Software
19062e
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19062e
+ *
19062e
+ */
19062e
+
19062e
+#ifdef HAVE_CONFIG_H
19062e
+#include <config.h>
19062e
+#endif
19062e
+
19062e
+#include <glib.h>
19062e
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
19062e
+#include <libudev.h>
19062e
+#include <dbus/dbus.h>
19062e
+#include <bluetooth/bluetooth.h>
19062e
+#include <bluetooth/sdp.h>
19062e
+#include <libusb.h>
19062e
+
19062e
+#include "plugin.h"
19062e
+#include "log.h"
19062e
+
19062e
+#include "adapter.h"
19062e
+#include "manager.h"
19062e
+#include "device.h"
19062e
+
19062e
+#include "storage.h"
19062e
+#include "sdp_lib.h"
19062e
+
19062e
+/* Vendor and product ID for the Sixaxis PS3 controller */
19062e
+#define VENDOR 0x054c
19062e
+#define PRODUCT 0x0268
19062e
+#define SIXAXIS_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
19062e
+#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
19062e
+
19062e
+static struct btd_device *create_cable_association(DBusConnection *conn,
19062e
+						    struct btd_adapter *adapter,
19062e
+						    const char *name,
19062e
+						    const char *address,
19062e
+						    guint32 vendor_id,
19062e
+						    guint32 product_id,
19062e
+						    const char *pnp_record)
19062e
+{
19062e
+	sdp_record_t *rec;
19062e
+	struct btd_device *device;
19062e
+	bdaddr_t src, dst;
19062e
+	char srcaddr[18];
19062e
+
19062e
+	device = adapter_find_device(adapter, address);
19062e
+	if (device == NULL) {
19062e
+		device = device_create(conn, adapter, address, BDADDR_BREDR);
19062e
+		if (device != NULL)
19062e
+			adapter_create_device_for_device(conn, adapter, device);
19062e
+	}
19062e
+	if (device != NULL) {
19062e
+		device_set_temporary(device, FALSE);
19062e
+		device_set_name(device, name);
19062e
+	}
19062e
+
19062e
+	str2ba(address, &dst);
19062e
+	adapter_get_address(adapter, &src;;
19062e
+	ba2str(&src, srcaddr);
19062e
+
19062e
+	write_device_name(&dst, &src, (char *) name);
19062e
+
19062e
+	/* Store the device's SDP record */
19062e
+	rec = record_from_string(pnp_record);
19062e
+	store_record(srcaddr, address, rec);
19062e
+	sdp_record_free(rec);
19062e
+	/* Set the device id */
19062e
+	store_device_id(srcaddr, address, 0xffff, vendor_id, product_id, 0);
19062e
+	/* Don't write a profile, it will be updated when the device connects */
19062e
+
19062e
+	write_trust(srcaddr, address, "[all]", TRUE);
19062e
+
19062e
+	return device;
19062e
+}
19062e
+
19062e
+static char *get_bdaddr(libusb_device_handle *devh, int itfnum)
19062e
+{
19062e
+	unsigned char msg[17];
19062e
+	char *address;
19062e
+	int res;
19062e
+
19062e
+	res = libusb_control_transfer(devh,
19062e
+				      LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
19062e
+				      0x01, 0x03f2, itfnum,
19062e
+				      (void*) msg, sizeof(msg),
19062e
+				      5000);
19062e
+
19062e
+	if (res < 0) {
19062e
+		DBG("Getting the device Bluetooth address failed");
19062e
+		return NULL;
19062e
+	}
19062e
+
19062e
+	address = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
19062e
+				  msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
19062e
+
19062e
+	DBG("Device Bluetooth address: %s\n", address);
19062e
+
19062e
+	return address;
19062e
+}
19062e
+
19062e
+static gboolean set_master_bdaddr(libusb_device_handle *devh, int itfnum, char *host)
19062e
+{
19062e
+	unsigned char msg[8];
19062e
+	int mac[6];
19062e
+	int res;
19062e
+
19062e
+	if (sscanf(host, "%X:%X:%X:%X:%X:%X",
19062e
+		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
19062e
+		return FALSE;
19062e
+	}
19062e
+
19062e
+	msg[0] = 0x01;
19062e
+	msg[1] = 0x00;
19062e
+	msg[2] = mac[0];
19062e
+	msg[3] = mac[1];
19062e
+	msg[4] = mac[2];
19062e
+	msg[5] = mac[3];
19062e
+	msg[6] = mac[4];
19062e
+	msg[7] = mac[5];
19062e
+
19062e
+	res = libusb_control_transfer(devh,
19062e
+				      LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
19062e
+				      0x09, 0x03f5, itfnum,
19062e
+				      (void*) msg, sizeof(msg),
19062e
+				      5000);
19062e
+
19062e
+	if (res < 0) {
19062e
+		DBG("Setting the master Bluetooth address failed");
19062e
+		return FALSE;
19062e
+	}
19062e
+
19062e
+	return TRUE;
19062e
+}
19062e
+static void handle_usb_device(struct btd_adapter *adapter,
19062e
+			      libusb_device *dev,
19062e
+			      struct libusb_config_descriptor *cfg,
19062e
+			      int itfnum,
19062e
+			      const struct libusb_interface_descriptor *alt)
19062e
+{
19062e
+	DBusConnection *conn;
19062e
+	libusb_device_handle *devh;
19062e
+	char *device_bdaddr;
19062e
+	char adapter_bdaddr[18];
19062e
+	struct btd_device *device;
19062e
+	bdaddr_t dst;
19062e
+
19062e
+	device_bdaddr = NULL;
19062e
+	conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
19062e
+	if (conn == NULL) {
19062e
+		DBG("Failed to get on the bus");
19062e
+		return;
19062e
+	}
19062e
+
19062e
+	if (libusb_open(dev, &devh) < 0) {
19062e
+		DBG("Can't open device");
19062e
+		goto bail;
19062e
+	}
19062e
+	libusb_detach_kernel_driver(devh, itfnum);
19062e
+
19062e
+	if (libusb_claim_interface(devh, itfnum) < 0) {
19062e
+		DBG("Can't claim interface %d", itfnum);
19062e
+		goto bail;
19062e
+	}
19062e
+
19062e
+	device_bdaddr = get_bdaddr(devh, itfnum);
19062e
+	if (device_bdaddr == NULL) {
19062e
+		DBG("Failed to get the Bluetooth address from the device");
19062e
+		goto bail;
19062e
+	}
19062e
+
19062e
+	device = create_cable_association(conn,
19062e
+					  adapter,
19062e
+					  "PLAYSTATION(R)3 Controller",
19062e
+					  device_bdaddr,
19062e
+					  VENDOR, PRODUCT, SIXAXIS_PNP_RECORD);
19062e
+	btd_device_add_uuid(device, HID_UUID);
19062e
+
19062e
+	adapter_get_address(adapter, &dst);
19062e
+	ba2str(&dst, adapter_bdaddr);
19062e
+	DBG("Adapter bdaddr %s", adapter_bdaddr);
19062e
+
19062e
+	if (set_master_bdaddr(devh, itfnum, adapter_bdaddr) == FALSE) {
19062e
+		DBG("Failed to set the master Bluetooth address");
19062e
+		goto bail;
19062e
+	}
19062e
+
19062e
+bail:
19062e
+	dbus_connection_unref(conn);
19062e
+	g_free(device_bdaddr);
19062e
+	libusb_release_interface(devh, itfnum);
19062e
+	/* We ignore errors from the reattach, as there's nothing we
19062e
+	 * can do about it */
19062e
+	libusb_attach_kernel_driver(devh, itfnum);
19062e
+	if (devh != NULL)
19062e
+		libusb_close(devh);
19062e
+}
19062e
+
19062e
+static void handle_device_plug(struct udev_device *udevice)
19062e
+{
19062e
+	struct btd_adapter *adapter;
19062e
+	guint i;
19062e
+
19062e
+	libusb_device **list, *usbdev;
19062e
+	ssize_t num_devices;
19062e
+	struct libusb_device_descriptor desc;
19062e
+	guint8 j;
19062e
+
19062e
+	if (g_strcmp0(udev_device_get_property_value(udevice, "ID_SERIAL"),
19062e
+		      "Sony_PLAYSTATION_R_3_Controller") != 0)
19062e
+		return;
19062e
+	/* Don't look at events with an associated driver */
19062e
+	if (udev_device_get_property_value(udevice, "ID_USB_DRIVER") != NULL)
19062e
+		return;
19062e
+
19062e
+	DBG("Found Sixaxis device");
19062e
+
19062e
+	/* Look for the default adapter */
19062e
+	adapter = manager_get_default_adapter();
19062e
+	if (adapter == NULL)
19062e
+		return;
19062e
+
19062e
+	/* Look for the USB device */
19062e
+	libusb_init(NULL);
19062e
+
19062e
+	num_devices = libusb_get_device_list(NULL, &list);
19062e
+	if (num_devices < 0) {
19062e
+		DBG("libusb_get_device_list failed");
19062e
+		return;
19062e
+	}
19062e
+
19062e
+	usbdev = NULL;
19062e
+	for (i = 0; i < num_devices; i++) {
19062e
+		char *path;
19062e
+
19062e
+		path = g_strdup_printf("%s/%03d/%03d", "/dev/bus/usb",
19062e
+				       libusb_get_bus_number(list[i]),
19062e
+				       libusb_get_device_address(list[i]));
19062e
+		if (g_strcmp0(path, udev_device_get_devnode(udevice)) == 0) {
19062e
+			g_free(path);
19062e
+			usbdev = libusb_ref_device(list[i]);
19062e
+			break;
19062e
+		}
19062e
+		g_free(path);
19062e
+	}
19062e
+
19062e
+	libusb_free_device_list(list, TRUE);
19062e
+	if (usbdev == NULL) {
19062e
+		DBG("Found a Sixaxis, but couldn't find it via libusb");
19062e
+		goto out;
19062e
+	}
19062e
+
19062e
+	if (libusb_get_device_descriptor(usbdev, &desc) < 0) {
19062e
+		DBG("libusb_get_device_descriptor() failed");
19062e
+		goto out;
19062e
+	}
19062e
+
19062e
+	/* Look for the interface number that interests us */
19062e
+	for (j = 0; j < desc.bNumConfigurations; j++) {
19062e
+		struct libusb_config_descriptor *config;
19062e
+		guint8 k;
19062e
+
19062e
+		if (libusb_get_config_descriptor(usbdev, j, &config) < 0) {
19062e
+			DBG("Failed to get config descriptor %d", j);
19062e
+			continue;
19062e
+		}
19062e
+
19062e
+		for (k = 0; k < config->bNumInterfaces; k++) {
19062e
+			const struct libusb_interface *itf = &config->interface[k];
19062e
+			int l;
19062e
+
19062e
+			for (l = 0; l < itf->num_altsetting ; l++) {
19062e
+				struct libusb_interface_descriptor alt;
19062e
+
19062e
+				alt = itf->altsetting[l];
19062e
+				if (alt.bInterfaceClass == 3) {
19062e
+					handle_usb_device(adapter, usbdev, config, l, &alt;;
19062e
+				}
19062e
+			}
19062e
+		}
19062e
+	}
19062e
+
19062e
+out:
19062e
+	if (usbdev != NULL)
19062e
+		libusb_unref_device(usbdev);
19062e
+	libusb_exit(NULL);
19062e
+}
19062e
+
19062e
+static gboolean device_event_idle(struct udev_device *udevice)
19062e
+{
19062e
+	handle_device_plug(udevice);
19062e
+	udev_device_unref(udevice);
19062e
+	return FALSE;
19062e
+}
19062e
+
19062e
+static struct udev *ctx = NULL;
19062e
+static struct udev_monitor *monitor = NULL;
19062e
+static guint watch_id = 0;
19062e
+
19062e
+static gboolean
19062e
+monitor_event(GIOChannel *source,
19062e
+	      GIOCondition condition,
19062e
+	      gpointer data)
19062e
+{
19062e
+	struct udev_device *udevice;
19062e
+
19062e
+	udevice = udev_monitor_receive_device(monitor);
19062e
+	if (udevice == NULL)
19062e
+		goto out;
19062e
+	if (g_strcmp0(udev_device_get_action(udevice), "add") != 0)
19062e
+		goto out;
19062e
+
19062e
+	g_timeout_add_seconds(1, (GSourceFunc) device_event_idle, udevice);
19062e
+
19062e
+out:
19062e
+	return TRUE;
19062e
+}
19062e
+
19062e
+
19062e
+static int cable_init(void)
19062e
+{
19062e
+	GIOChannel *channel;
19062e
+
19062e
+	DBG("Setup cable plugin");
19062e
+
19062e
+	ctx = udev_new();
19062e
+	monitor = udev_monitor_new_from_netlink(ctx, "udev");
19062e
+	if (monitor == NULL) {
19062e
+		error ("Could not get udev monitor");
19062e
+		return -1;
19062e
+	}
19062e
+
19062e
+	/* Listen for newly connected usb device */
19062e
+	udev_monitor_filter_add_match_subsystem_devtype(monitor,
19062e
+							"usb", NULL);
19062e
+	udev_monitor_enable_receiving(monitor);
19062e
+
19062e
+	channel = g_io_channel_unix_new(udev_monitor_get_fd(monitor));
19062e
+	watch_id = g_io_add_watch(channel, G_IO_IN, monitor_event, NULL);
19062e
+	g_io_channel_unref(channel);
19062e
+
19062e
+	return 0;
19062e
+}
19062e
+
19062e
+static void cable_exit(void)
19062e
+{
19062e
+	DBG("Cleanup cable plugin");
19062e
+
19062e
+	if (watch_id != 0) {
19062e
+		g_source_remove(watch_id);
19062e
+		watch_id = 0;
19062e
+	}
19062e
+	if (monitor != NULL) {
19062e
+		udev_monitor_unref(monitor);
19062e
+		monitor = NULL;
19062e
+	}
19062e
+	if (ctx != NULL) {
19062e
+		udev_unref(ctx);
19062e
+		ctx = NULL;
19062e
+	}
19062e
+}
19062e
+
19062e
+BLUETOOTH_PLUGIN_DEFINE(cable, VERSION,
19062e
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, cable_init, cable_exit)
19062e
diff --git a/src/adapter.c b/src/adapter.c
19062e
index 6e04faf..0488891 100644
19062e
--- a/src/adapter.c
19062e
+++ b/src/adapter.c
19062e
@@ -952,6 +952,25 @@ static struct btd_device *adapter_create_device(DBusConnection *conn,
19062e
 	return device;
19062e
 }
19062e
 
19062e
+void adapter_create_device_for_device(DBusConnection *conn,
19062e
+				      struct btd_adapter *adapter,
19062e
+				      struct btd_device *device)
19062e
+{
19062e
+	const char *path;
19062e
+
19062e
+	device_set_temporary(device, TRUE);
19062e
+
19062e
+	adapter->devices = g_slist_append(adapter->devices, device);
19062e
+
19062e
+	path = device_get_path(device);
19062e
+	g_dbus_emit_signal(conn, adapter->path,
19062e
+			ADAPTER_INTERFACE, "DeviceCreated",
19062e
+			DBUS_TYPE_OBJECT_PATH, &path,
19062e
+			DBUS_TYPE_INVALID);
19062e
+
19062e
+	adapter_update_devices(adapter);
19062e
+}
19062e
+
19062e
 void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
19062e
 						struct btd_device *device,
19062e
 						gboolean remove_storage)
19062e
diff --git a/src/adapter.h b/src/adapter.h
19062e
index b7ea62b..ac0aa2e 100644
19062e
--- a/src/adapter.h
19062e
+++ b/src/adapter.h
19062e
@@ -114,6 +114,9 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
19062e
 					uint8_t *data, uint8_t data_len);
19062e
 void adapter_emit_device_found(struct btd_adapter *adapter,
19062e
 						struct remote_dev_info *dev);
19062e
+void adapter_create_device_for_device(DBusConnection *conn,
19062e
+				      struct btd_adapter *adapter,
19062e
+				      struct btd_device *device);
19062e
 void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
19062e
 int adapter_set_name(struct btd_adapter *adapter, const char *name);
19062e
 void adapter_name_changed(struct btd_adapter *adapter, const char *name);
19062e
-- 
19062e
1.7.10.2
19062e