a4f8914
From 7194839445edb3fd112b2bc79878c303e3b7c9e2 Mon Sep 17 00:00:00 2001
22e68ea
From: Bastien Nocera <hadess@hadess.net>
ad8c9b3
Date: Tue, 1 Sep 2009 17:32:48 +0100
22e68ea
Subject: [PATCH] Add sixaxis cable-pairing plugin
22e68ea
a4f8914
Implement the old "sixpair" using libudev and libusb-1.0.
22e68ea
22e68ea
When a Sixaxis device is plugged in, events are filtered, and
22e68ea
the device is selected, poked around to set the default Bluetooth
22e68ea
address, and added to the database of the current default adapter.
22e68ea
---
a4f8914
 Makefile.am     |    9 +-
61a8de2
 acinclude.m4    |   16 +++
ad8c9b3
 configure.ac    |    1 +
a4f8914
 plugins/cable.c |  384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
a4f8914
 4 files changed, 408 insertions(+), 2 deletions(-)
22e68ea
 create mode 100644 plugins/cable.c
22e68ea
ad8c9b3
diff --git a/Makefile.am b/Makefile.am
a4f8914
index c8337d6..e5eccdf 100644
ad8c9b3
--- a/Makefile.am
ad8c9b3
+++ b/Makefile.am
a4f8914
@@ -162,6 +162,11 @@ builtin_modules += service
ad8c9b3
 builtin_sources += plugins/service.c
ad8c9b3
 endif
ad8c9b3
 
ad8c9b3
+if CABLE
a4f8914
+builtin_modules += cable
a4f8914
+builtin_sources += plugins/cable.c
ad8c9b3
+endif
ad8c9b3
+
ad8c9b3
 builtin_modules += hciops
ad8c9b3
 builtin_sources += plugins/hciops.c
ad8c9b3
 
a4f8914
@@ -192,7 +197,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
a4f8914
 			src/dbus-common.c src/dbus-common.h \
a4f8914
 			src/dbus-hci.h src/dbus-hci.c
a4f8914
 src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
a4f8914
-							@CAPNG_LIBS@ -ldl
a4f8914
+							@CAPNG_LIBS@ @CABLE_LIBS@ -ldl
a4f8914
 src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
a4f8914
 					-Wl,--version-script=src/bluetooth.ver
a4f8914
 src_bluetoothd_DEPENDENCIES = src/bluetooth.ver lib/libbluetooth.la
a4f8914
@@ -305,7 +310,7 @@ EXTRA_DIST += doc/manager-api.txt \
a4f8914
 
a4f8914
 AM_YFLAGS = -d
a4f8914
 
a4f8914
-AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
a4f8914
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ @CABLE_CFLAGS@ \
a4f8914
 		-DBLUETOOTH_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
a4f8914
 
a4f8914
 INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
ad8c9b3
diff --git a/acinclude.m4 b/acinclude.m4
a4f8914
index e7d1c32..10e5241 100644
ad8c9b3
--- a/acinclude.m4
ad8c9b3
+++ b/acinclude.m4
ad8c9b3
@@ -142,6 +142,12 @@ AC_DEFUN([AC_PATH_USB], [
ad8c9b3
 			[Define to 1 if you need the usb_interrupt_read() function.]))
ad8c9b3
 ])
ad8c9b3
 
ad8c9b3
+AC_DEFUN([AC_PATH_CABLE], [
a4f8914
+	PKG_CHECK_MODULES(CABLE, libudev libusb-1.0, cable_found=yes, cable_found=no)
ad8c9b3
+	AC_SUBST(CABLE_CFLAGS)
ad8c9b3
+	AC_SUBST(CABLE_LIBS)
ad8c9b3
+])
ad8c9b3
+
ad8c9b3
 AC_DEFUN([AC_PATH_NETLINK], [
ad8c9b3
 	PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes, netlink_found=no)
ad8c9b3
 	AC_SUBST(NETLINK_CFLAGS)
6daa964
@@ -170,6 +176,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
ad8c9b3
 	netlink_enable=no
ad8c9b3
 	hal_enable=${hal_found}
ad8c9b3
 	usb_enable=${usb_found}
ad8c9b3
+	cable_enable=${cable_found}
ad8c9b3
 	alsa_enable=${alsa_found}
ad8c9b3
 	gstreamer_enable=${gstreamer_found}
ad8c9b3
 	audio_enable=yes
6daa964
@@ -239,6 +246,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
ad8c9b3
 		usb_enable=${enableval}
ad8c9b3
 	])
ad8c9b3
 
ad8c9b3
+	AC_ARG_ENABLE(cable, AC_HELP_STRING([--enable-cable], [enable DeviceKit support]), [
ad8c9b3
+		cable_enable=${enableval}
ad8c9b3
+	])
ad8c9b3
+
ad8c9b3
 	AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
ad8c9b3
 		netlink_enable=${enableval}
ad8c9b3
 	])
61a8de2
@@ -326,6 +337,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
6daa964
 		AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have capabilities library.])
6daa964
 	fi
6daa964
 
61a8de2
+	if (test "${cable_enable}" = "yes" && test "${cable_found}" = "yes"); then
61a8de2
+		AC_DEFINE(HAVE_CABLE, 1, [Define to 1 if you have libcable.])
61a8de2
+	fi
61a8de2
+
ad8c9b3
 	AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes")
61a8de2
 	AM_CONDITIONAL(NETLINK, test "${netlink_enable}" = "yes" && test "${netlink_found}" = "yes")
61a8de2
 	AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes")
61a8de2
@@ -350,4 +365,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
ad8c9b3
 	AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
ad8c9b3
 	AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
ad8c9b3
 	AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
ad8c9b3
+	AM_CONDITIONAL(CABLE, test "${cable_enable}" = "yes" && test "${cable_found}" = "yes")
ad8c9b3
 ])
22e68ea
diff --git a/configure.ac b/configure.ac
6daa964
index b93cca0..5df134f 100644
22e68ea
--- a/configure.ac
22e68ea
+++ b/configure.ac
ad8c9b3
@@ -40,6 +40,7 @@ AC_PATH_GLIB
22e68ea
 AC_PATH_ALSA
22e68ea
 AC_PATH_GSTREAMER
22e68ea
 AC_PATH_USB
22e68ea
+AC_PATH_CABLE
22e68ea
 AC_PATH_NETLINK
22e68ea
 AC_PATH_SNDFILE
6daa964
 AC_PATH_CAPNG
22e68ea
diff --git a/plugins/cable.c b/plugins/cable.c
22e68ea
new file mode 100644
a4f8914
index 0000000..0b7cc7a
22e68ea
--- /dev/null
22e68ea
+++ b/plugins/cable.c
a4f8914
@@ -0,0 +1,384 @@
22e68ea
+/*
22e68ea
+ *
22e68ea
+ *  BlueZ - Bluetooth protocol stack for Linux
22e68ea
+ *
22e68ea
+ *  Copyright (C) 2009  Bastien Nocera <hadess@hadess.net>
22e68ea
+ *
22e68ea
+ *
22e68ea
+ *  This program is free software; you can redistribute it and/or modify
22e68ea
+ *  it under the terms of the GNU General Public License as published by
22e68ea
+ *  the Free Software Foundation; either version 2 of the License, or
22e68ea
+ *  (at your option) any later version.
22e68ea
+ *
22e68ea
+ *  This program is distributed in the hope that it will be useful,
22e68ea
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22e68ea
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22e68ea
+ *  GNU General Public License for more details.
22e68ea
+ *
22e68ea
+ *  You should have received a copy of the GNU General Public License
22e68ea
+ *  along with this program; if not, write to the Free Software
22e68ea
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22e68ea
+ *
22e68ea
+ */
22e68ea
+
22e68ea
+#ifdef HAVE_CONFIG_H
22e68ea
+#include <config.h>
22e68ea
+#endif
22e68ea
+
a4f8914
+#include <glib.h>
a4f8914
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
a4f8914
+#include <libudev.h>
22e68ea
+#include <dbus/dbus.h>
22e68ea
+#include <bluetooth/bluetooth.h>
22e68ea
+#include <bluetooth/sdp.h>
22e68ea
+#include <libusb.h>
22e68ea
+
22e68ea
+#include "plugin.h"
22e68ea
+#include "logging.h"
22e68ea
+
22e68ea
+#include "manager.h"
22e68ea
+#include "adapter.h"
22e68ea
+#include "device.h"
22e68ea
+
22e68ea
+#include "storage.h"
22e68ea
+#include "sdp_lib.h"
22e68ea
+
22e68ea
+/* Vendor and product ID for the Sixaxis PS3 controller */
22e68ea
+#define VENDOR 0x054c
22e68ea
+#define PRODUCT 0x0268
22e68ea
+#define SIXAXIS_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
22e68ea
+#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
22e68ea
+
48f7337
+static struct btd_device *create_cable_association(DBusConnection *conn,
48f7337
+						    struct btd_adapter *adapter,
48f7337
+						    const char *name,
48f7337
+						    const char *address,
48f7337
+						    guint32 vendor_id,
48f7337
+						    guint32 product_id,
48f7337
+						    const char *pnp_record)
22e68ea
+{
22e68ea
+	sdp_record_t *rec;
22e68ea
+	struct btd_device *device;
22e68ea
+	bdaddr_t src, dst;
22e68ea
+	char srcaddr[18];
22e68ea
+
22e68ea
+	device = adapter_find_device(adapter, address);
22e68ea
+	if (device == NULL)
22e68ea
+		device = adapter_create_device(conn, adapter, address);
22e68ea
+	if (device != NULL) {
22e68ea
+		device_set_temporary(device, FALSE);
22e68ea
+		device_set_name(device, name);
22e68ea
+	}
22e68ea
+
22e68ea
+	str2ba(address, &dst);
22e68ea
+	adapter_get_address(adapter, &src;;
22e68ea
+	ba2str(&src, srcaddr);
22e68ea
+
22e68ea
+	write_device_name(&dst, &src, (char *) name);
22e68ea
+
22e68ea
+	/* Store the device's SDP record */
22e68ea
+	rec = record_from_string(pnp_record);
22e68ea
+	store_record(srcaddr, address, rec);
22e68ea
+	sdp_record_free(rec);
22e68ea
+	/* Set the device id */
22e68ea
+	store_device_id(srcaddr, address, 0xffff, vendor_id, product_id, 0);
22e68ea
+	/* Don't write a profile, it will be updated when the device connects */
22e68ea
+
22e68ea
+	write_trust(srcaddr, address, "[all]", TRUE);
22e68ea
+
22e68ea
+	return device;
22e68ea
+}
22e68ea
+
22e68ea
+static char *get_bdaddr(libusb_device_handle *devh, int itfnum)
22e68ea
+{
22e68ea
+	unsigned char msg[17];
22e68ea
+	char *address;
22e68ea
+	int res;
22e68ea
+
22e68ea
+	res = libusb_control_transfer(devh,
22e68ea
+				      LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
22e68ea
+				      0x01, 0x03f2, itfnum,
22e68ea
+				      (void*) msg, sizeof(msg),
22e68ea
+				      5000);
22e68ea
+
22e68ea
+	if (res < 0) {
22e68ea
+		debug("Getting the device Bluetooth address failed");
22e68ea
+		return NULL;
22e68ea
+	}
22e68ea
+
22e68ea
+	address = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
22e68ea
+				  msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
22e68ea
+
22e68ea
+	debug("Device Bluetooth address: %s\n", address);
22e68ea
+
22e68ea
+	return address;
22e68ea
+}
22e68ea
+
22e68ea
+static gboolean set_master_bdaddr(libusb_device_handle *devh, int itfnum, char *host)
22e68ea
+{
22e68ea
+	unsigned char msg[8];
22e68ea
+	int mac[6];
22e68ea
+	int res;
22e68ea
+
22e68ea
+	if (sscanf(host, "%X:%X:%X:%X:%X:%X",
22e68ea
+		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
22e68ea
+		return FALSE;
22e68ea
+	}
22e68ea
+
22e68ea
+	msg[0] = 0x01;
22e68ea
+	msg[1] = 0x00;
22e68ea
+	msg[2] = mac[0];
22e68ea
+	msg[3] = mac[1];
22e68ea
+	msg[4] = mac[2];
22e68ea
+	msg[5] = mac[3];
22e68ea
+	msg[6] = mac[4];
22e68ea
+	msg[7] = mac[5];
22e68ea
+
22e68ea
+	res = libusb_control_transfer(devh,
22e68ea
+				      LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
22e68ea
+				      0x09, 0x03f5, itfnum,
22e68ea
+				      (void*) msg, sizeof(msg),
22e68ea
+				      5000);
22e68ea
+
22e68ea
+	if (res < 0) {
22e68ea
+		debug("Setting the master Bluetooth address failed");
22e68ea
+		return FALSE;
22e68ea
+	}
22e68ea
+
22e68ea
+	return TRUE;
22e68ea
+}
22e68ea
+static void handle_usb_device(struct btd_adapter *adapter,
22e68ea
+			      libusb_device *dev,
22e68ea
+			      struct libusb_config_descriptor *cfg,
22e68ea
+			      int itfnum,
22e68ea
+			      const struct libusb_interface_descriptor *alt)
22e68ea
+{
22e68ea
+	DBusConnection *conn;
22e68ea
+	libusb_device_handle *devh;
22e68ea
+	char *device_bdaddr;
22e68ea
+	char adapter_bdaddr[18];
22e68ea
+	struct btd_device *device;
22e68ea
+	bdaddr_t dst;
22e68ea
+
22e68ea
+	conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
22e68ea
+	if (conn == NULL) {
22e68ea
+		debug("Failed to get on the bus");
22e68ea
+		return;
22e68ea
+	}
22e68ea
+
22e68ea
+	if (libusb_open(dev, &devh) < 0) {
22e68ea
+		debug("Can't open device");
22e68ea
+		goto bail;
22e68ea
+	}
22e68ea
+	libusb_detach_kernel_driver(devh, itfnum);
22e68ea
+
22e68ea
+	if (libusb_claim_interface(devh, itfnum) < 0) {
22e68ea
+		debug("Can't claim interface %d", itfnum);
22e68ea
+		goto bail;
22e68ea
+	}
22e68ea
+
22e68ea
+	device_bdaddr = get_bdaddr(devh, itfnum);
22e68ea
+	if (device_bdaddr == NULL) {
22e68ea
+		debug("Failed to get the Bluetooth address from the device");
22e68ea
+		goto bail;
22e68ea
+	}
22e68ea
+
22e68ea
+	device = create_cable_association(conn,
22e68ea
+					  adapter,
22e68ea
+					  "PLAYSTATION(R)3 Controller",
22e68ea
+					  device_bdaddr,
22e68ea
+					  VENDOR, PRODUCT, SIXAXIS_PNP_RECORD);
22e68ea
+	btd_device_add_uuid(device, HID_UUID);
22e68ea
+
22e68ea
+	adapter_get_address(adapter, &dst);
22e68ea
+	ba2str(&dst, adapter_bdaddr);
22e68ea
+	debug("Adapter bdaddr %s", adapter_bdaddr);
22e68ea
+
22e68ea
+	if (set_master_bdaddr(devh, itfnum, adapter_bdaddr) == FALSE) {
22e68ea
+		debug("Failed to set the master Bluetooth address");
22e68ea
+		goto bail;
22e68ea
+	}
22e68ea
+
22e68ea
+bail:
22e68ea
+	dbus_connection_unref(conn);
22e68ea
+	g_free(device_bdaddr);
22e68ea
+	libusb_release_interface(devh, itfnum);
22e68ea
+	/* We ignore errors from the reattach, as there's nothing we
22e68ea
+	 * can do about it */
22e68ea
+	libusb_attach_kernel_driver(devh, itfnum);
22e68ea
+	if (devh != NULL)
22e68ea
+		libusb_close(devh);
22e68ea
+}
22e68ea
+
a4f8914
+static void handle_device_plug(struct udev_device *udevice)
22e68ea
+{
22e68ea
+	struct btd_adapter *adapter;
22e68ea
+	int adapter_id;
22e68ea
+	guint i;
22e68ea
+
22e68ea
+	libusb_device **list, *usbdev;
22e68ea
+	ssize_t num_devices;
22e68ea
+	struct libusb_device_descriptor desc;
22e68ea
+	guint8 j;
22e68ea
+
a4f8914
+	if (g_strcmp0(udev_device_get_property_value(udevice, "ID_SERIAL"),
a4f8914
+		      "Sony_PLAYSTATION_R_3_Controller") != 0)
22e68ea
+		return;
22e68ea
+	/* Don't look at events with an associated driver */
a4f8914
+	if (udev_device_get_property_value(udevice, "ID_USB_DRIVER") != NULL)
22e68ea
+		return;
22e68ea
+
22e68ea
+	debug("Found Sixaxis device");
22e68ea
+
22e68ea
+	/* Look for the default adapter */
22e68ea
+	adapter_id = manager_get_default_adapter();
22e68ea
+	if (adapter_id == -1) {
22e68ea
+		debug("No adapters, exiting");
22e68ea
+		return;
22e68ea
+	}
22e68ea
+	adapter = manager_find_adapter_by_id(adapter_id);
22e68ea
+	if (adapter == NULL)
22e68ea
+		return;
22e68ea
+
22e68ea
+	/* Look for the USB device */
22e68ea
+	libusb_init(NULL);
22e68ea
+
22e68ea
+	num_devices = libusb_get_device_list(NULL, &list);
22e68ea
+	if (num_devices < 0) {
22e68ea
+		debug("libusb_get_device_list failed");
22e68ea
+		return;
22e68ea
+	}
22e68ea
+
22e68ea
+	usbdev = NULL;
22e68ea
+	for (i = 0; i < num_devices; i++) {
22e68ea
+		char *path;
22e68ea
+
22e68ea
+		path = g_strdup_printf("%s/%03d/%03d", "/dev/bus/usb",
22e68ea
+				       libusb_get_bus_number(list[i]),
22e68ea
+				       libusb_get_device_address(list[i]));
a4f8914
+		if (g_strcmp0(path, udev_device_get_devnode(udevice)) == 0) {
22e68ea
+			g_free(path);
22e68ea
+			usbdev = libusb_ref_device(list[i]);
22e68ea
+			break;
22e68ea
+		}
22e68ea
+		g_free(path);
22e68ea
+	}
22e68ea
+
22e68ea
+	libusb_free_device_list(list, TRUE);
22e68ea
+	if (usbdev == NULL) {
22e68ea
+		debug("Found a Sixaxis, but couldn't find it via libusb");
22e68ea
+		goto out;
22e68ea
+	}
22e68ea
+
22e68ea
+	if (libusb_get_device_descriptor(usbdev, &desc) < 0) {
22e68ea
+		debug("libusb_get_device_descriptor() failed");
22e68ea
+		goto out;
22e68ea
+	}
22e68ea
+
22e68ea
+	/* Look for the interface number that interests us */
22e68ea
+	for (j = 0; j < desc.bNumConfigurations; j++) {
22e68ea
+		struct libusb_config_descriptor *config;
22e68ea
+		guint8 k;
22e68ea
+
22e68ea
+		if (libusb_get_config_descriptor(usbdev, j, &config) < 0) {
22e68ea
+			debug("Failed to get config descriptor %d", j);
22e68ea
+			continue;
22e68ea
+		}
22e68ea
+
22e68ea
+		for (k = 0; k < config->bNumInterfaces; k++) {
22e68ea
+			const struct libusb_interface *itf = &config->interface[k];
22e68ea
+			int l;
22e68ea
+
22e68ea
+			for (l = 0; l < itf->num_altsetting ; l++) {
22e68ea
+				struct libusb_interface_descriptor alt;
22e68ea
+
22e68ea
+				alt = itf->altsetting[l];
22e68ea
+				if (alt.bInterfaceClass == 3) {
22e68ea
+					handle_usb_device(adapter, usbdev, config, l, &alt;;
22e68ea
+				}
22e68ea
+			}
22e68ea
+		}
22e68ea
+	}
22e68ea
+
22e68ea
+out:
22e68ea
+	if (usbdev != NULL)
22e68ea
+		libusb_unref_device(usbdev);
22e68ea
+	libusb_exit(NULL);
22e68ea
+}
22e68ea
+
a4f8914
+static gboolean device_event_idle(struct udev_device *udevice)
22e68ea
+{
a4f8914
+	handle_device_plug(udevice);
a4f8914
+	udev_device_unref(udevice);
22e68ea
+	return FALSE;
22e68ea
+}
22e68ea
+
a4f8914
+static struct udev *ctx = NULL;
a4f8914
+static struct udev_monitor *monitor = NULL;
a4f8914
+static guint watch_id = 0;
a4f8914
+
a4f8914
+static gboolean
a4f8914
+monitor_event(GIOChannel *source,
a4f8914
+	      GIOCondition condition,
a4f8914
+	      gpointer data)
22e68ea
+{
a4f8914
+	struct udev_device *udevice;
a4f8914
+
a4f8914
+	udevice = udev_monitor_receive_device(monitor);
a4f8914
+	if (udevice == NULL)
a4f8914
+		goto out;
a4f8914
+	if (g_strcmp0(udev_device_get_action(udevice), "add") != 0)
a4f8914
+		goto out;
a4f8914
+
a4f8914
+	g_timeout_add_seconds(1, (GSourceFunc) device_event_idle, udevice);
a4f8914
+
a4f8914
+out:
a4f8914
+	return TRUE;
22e68ea
+}
22e68ea
+
22e68ea
+
22e68ea
+static int cable_init(void)
22e68ea
+{
a4f8914
+	GIOChannel *channel;
22e68ea
+
22e68ea
+	debug("Setup cable plugin");
22e68ea
+
a4f8914
+	ctx = udev_new();
a4f8914
+	monitor = udev_monitor_new_from_netlink(ctx, "udev");
a4f8914
+	if (monitor == NULL) {
a4f8914
+		error ("Could not get udev monitor");
a4f8914
+		return -1;
a4f8914
+	}
22e68ea
+
a4f8914
+	/* Listen for newly connected usb device */
a4f8914
+	udev_monitor_filter_add_match_subsystem_devtype(monitor,
a4f8914
+							"usb", NULL);
a4f8914
+	udev_monitor_enable_receiving(monitor);
22e68ea
+
a4f8914
+	channel = g_io_channel_unix_new(udev_monitor_get_fd(monitor));
a4f8914
+	watch_id = g_io_add_watch(channel, G_IO_IN, monitor_event, NULL);
a4f8914
+	g_io_channel_unref(channel);
22e68ea
+
22e68ea
+	return 0;
22e68ea
+}
22e68ea
+
22e68ea
+static void cable_exit(void)
22e68ea
+{
22e68ea
+	debug("Cleanup cable plugin");
22e68ea
+
a4f8914
+	if (watch_id != 0) {
a4f8914
+		g_source_remove(watch_id);
a4f8914
+		watch_id = 0;
a4f8914
+	}
a4f8914
+	if (monitor != NULL) {
a4f8914
+		udev_monitor_unref(monitor);
a4f8914
+		monitor = NULL;
a4f8914
+	}
a4f8914
+	if (ctx != NULL) {
a4f8914
+		udev_unref(ctx);
a4f8914
+		ctx = NULL;
22e68ea
+	}
22e68ea
+}
22e68ea
+
22e68ea
+BLUETOOTH_PLUGIN_DEFINE(cable, VERSION,
22e68ea
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, cable_init, cable_exit)
22e68ea
-- 
6daa964
1.6.4.4
22e68ea