All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Add sixaxis cable-pairing plugin
@ 2009-06-04  9:28 Bastien Nocera
  2009-06-04 18:13 ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-06-04  9:28 UTC (permalink / raw)
  To: BlueZ development

[-- Attachment #1: Type: text/plain, Size: 88 bytes --]

Works for me, comments welcome.

It uses gudev. See http://blog.fubar.dk/?p=106

Cheers

[-- Attachment #2: 0001-Add-sixaxis-cable-pairing-plugin.patch --]
[-- Type: text/x-patch, Size: 14610 bytes --]

>From f23a9556acf6308e217b11e0a882e89d799f2517 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Thu, 4 Jun 2009 10:23:58 +0100
Subject: [PATCH] Add sixaxis cable-pairing plugin

Implement the old "sixpair" using gudev (a GObject layer on top
of udev's monitoring system), and libusb-1.0.

When a Sixaxis device is plugged in, events are filtered, and
the device is selected, poked around to set the default Bluetooth
address, and added to the database of the current default adapter.
---
 acinclude.m4        |   16 +++
 configure.ac        |    1 +
 plugins/Makefile.am |   11 ++-
 plugins/cable.c     |  361 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 388 insertions(+), 1 deletions(-)
 create mode 100644 plugins/cable.c

diff --git a/acinclude.m4 b/acinclude.m4
index eb7cdeb..dac1120 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -159,6 +159,12 @@ AC_DEFUN([AC_PATH_USB], [
 			[Define to 1 if you need the usb_interrupt_read() function.]))
 ])
 
+AC_DEFUN([AC_PATH_CABLE], [
+	PKG_CHECK_MODULES(CABLE, gudev-1.0 libusb-1.0, cable_found=yes, cable_found=no)
+	AC_SUBST(CABLE_CFLAGS)
+	AC_SUBST(CABLE_LIBS)
+])
+
 AC_DEFUN([AC_PATH_NETLINK], [
 	PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes, netlink_found=no)
 	AC_SUBST(NETLINK_CFLAGS)
@@ -179,6 +185,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	netlink_enable=no
 	hal_enable=${hal_found}
 	usb_enable=${usb_found}
+	cable_enable=${cable_found}
 	alsa_enable=${alsa_found}
 	gstreamer_enable=${gstreamer_found}
 	audio_enable=yes
@@ -241,6 +248,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		usb_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(cable, AC_HELP_STRING([--enable-cable], [enable DeviceKit support]), [
+		cable_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
 		netlink_enable=${enableval}
 	])
@@ -324,6 +335,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
 	fi
 
+	if (test "${cable_enable}" = "yes" && test "${cable_found}" = "yes"); then
+		AC_DEFINE(HAVE_CABLE, 1, [Define to 1 if you have libcable.])
+	fi
+
 	AC_SUBST([BLUEZ_CFLAGS], ['-I$(top_builddir)/include'])
 	AC_SUBST([BLUEZ_LIBS], ['$(top_builddir)/lib/libbluetooth.la'])
 
@@ -357,4 +372,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
 	AM_CONDITIONAL(INITSCRIPTS, test "${initscripts_enable}" = "yes")
 	AM_CONDITIONAL(PCMCIARULES, test "${pcmciarules_enable}" = "yes")
+	AM_CONDITIONAL(CABLE, test "${cable_enable}" = "yes" && test "${cable_found}" = "yes")
 ])
diff --git a/configure.ac b/configure.ac
index 1686d18..339d45c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,7 @@ AC_PATH_GLIB
 AC_PATH_ALSA
 AC_PATH_GSTREAMER
 AC_PATH_USB
+AC_PATH_CABLE
 AC_PATH_NETLINK
 AC_PATH_SNDFILE
 
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 9d9f970..e43584a 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -26,10 +26,16 @@ builtin_sources += hal.c
 builtin_modules += storage
 builtin_sources += storage.c
 
+if CABLE
+plugin_LTLIBRARIES += cable.la
+cable_la_LIBADD = @CABLE_CFLAGS@
+endif
+
 noinst_LTLIBRARIES = libbuiltin.la echo.la
 
 libbuiltin_la_SOURCES = $(builtin_sources)
 libbuiltin_la_LDFLAGS =
+libbuiltin_la_LIBADD = @CABLE_LIBS@
 libbuiltin_la_CFLAGS = $(AM_CFLAGS) \
 			$(builtin_cflags) -DBLUETOOTH_PLUGIN_BUILTIN
 
@@ -40,7 +46,7 @@ nodist_libbuiltin_la_SOURCES = $(BUILT_SOURCES)
 AM_LDFLAGS = -module -avoid-version -no-undefined
 
 AM_CFLAGS = -fvisibility=hidden @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ \
-			@GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@
+			@GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@ @CABLE_CFLAGS@
 
 INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
 
@@ -49,6 +55,7 @@ CLEANFILES = $(BUILT_SOURCES)
 MAINTAINERCLEANFILES = Makefile.in
 
 builtin.h:
+	echo $(builtin_modules)
 	echo "" > $@
 	list='$(builtin_modules)'; for i in $$list; \
 	  do echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$$i;" >> $@; done
@@ -63,9 +70,11 @@ all-local:
 	@$(LN_S) -f $(top_srcdir)/audio/.libs/audio.so
 	@$(LN_S) -f $(top_srcdir)/serial/.libs/serial.so
 	@$(LN_S) -f $(top_srcdir)/network/.libs/network.so
+	@$(LN_S) -f $(top_srcdir)/plugins/.libs/cable.so
 
 clean-local:
 	@rm -f network.so
 	@rm -f serial.so
 	@rm -f audio.so
 	@rm -f input.so
+	@rm -f cable.so
diff --git a/plugins/cable.c b/plugins/cable.c
new file mode 100644
index 0000000..9f24b55
--- /dev/null
+++ b/plugins/cable.c
@@ -0,0 +1,361 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2009  Bastien Nocera <hadess@hadess.net>
+ *
+ *
+ *  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
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+#include <dbus/dbus.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <libusb.h>
+
+#include "plugin.h"
+#include "logging.h"
+
+#include "manager.h"
+#include "adapter.h"
+#include "device.h"
+
+#include "storage.h"
+#include "sdp_lib.h"
+
+/* Vendor and product ID for the Sixaxis PS3 controller */
+#define VENDOR 0x054c
+#define PRODUCT 0x0268
+#define SIXAXIS_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
+#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
+
+struct btd_device *create_cable_association(DBusConnection *conn,
+					    struct btd_adapter *adapter,
+					    const char *name,
+					    const char *address,
+					    guint32 vendor_id,
+					    guint32 product_id,
+					    const char *pnp_record)
+{
+	sdp_record_t *rec;
+	struct btd_device *device;
+	bdaddr_t src, dst;
+	char srcaddr[18];
+
+	device = adapter_find_device(adapter, address);
+	if (device == NULL)
+		device = adapter_create_device(conn, adapter, address);
+	if (device != NULL) {
+		device_set_temporary(device, FALSE);
+		device_set_name(device, name);
+	}
+
+	str2ba(address, &dst);
+	adapter_get_address(adapter, &src);
+	ba2str(&src, srcaddr);
+
+	write_device_name(&dst, &src, (char *) name);
+
+	/* Store the device's SDP record */
+	rec = record_from_string(pnp_record);
+	store_record(srcaddr, address, rec);
+	sdp_record_free(rec);
+	/* Set the device id */
+	store_device_id(srcaddr, address, 0xffff, vendor_id, product_id, 0);
+	/* Don't write a profile, it will be updated when the device connects */
+
+	write_trust(srcaddr, address, "[all]", TRUE);
+
+	return device;
+}
+
+static char *get_bdaddr(libusb_device_handle *devh, int itfnum)
+{
+	unsigned char msg[17];
+	char *address;
+	int res;
+
+	res = libusb_control_transfer(devh,
+				      LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+				      0x01, 0x03f2, itfnum,
+				      (void*) msg, sizeof(msg),
+				      5000);
+
+	if (res < 0) {
+		debug("Getting the device Bluetooth address failed");
+		return NULL;
+	}
+
+	address = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
+				  msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
+
+	debug("Device Bluetooth address: %s\n", address);
+
+	return address;
+}
+
+static gboolean set_master_bdaddr(libusb_device_handle *devh, int itfnum, char *host)
+{
+	unsigned char msg[8];
+	int mac[6];
+	int res;
+
+	if (sscanf(host, "%X:%X:%X:%X:%X:%X",
+		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
+		return FALSE;
+	}
+
+	msg[0] = 0x01;
+	msg[1] = 0x00;
+	msg[2] = mac[0];
+	msg[3] = mac[1];
+	msg[4] = mac[2];
+	msg[5] = mac[3];
+	msg[6] = mac[4];
+	msg[7] = mac[5];
+
+	res = libusb_control_transfer(devh,
+				      LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+				      0x09, 0x03f5, itfnum,
+				      (void*) msg, sizeof(msg),
+				      5000);
+
+	if (res < 0) {
+		debug("Setting the master Bluetooth address failed");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+static void handle_usb_device(struct btd_adapter *adapter,
+			      libusb_device *dev,
+			      struct libusb_config_descriptor *cfg,
+			      int itfnum,
+			      const struct libusb_interface_descriptor *alt)
+{
+	DBusConnection *conn;
+	libusb_device_handle *devh;
+	char *device_bdaddr;
+	char adapter_bdaddr[18];
+	struct btd_device *device;
+	bdaddr_t dst;
+
+	conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (conn == NULL) {
+		debug("Failed to get on the bus");
+		return;
+	}
+
+	if (libusb_open(dev, &devh) < 0) {
+		debug("Can't open device");
+		goto bail;
+	}
+	libusb_detach_kernel_driver(devh, itfnum);
+
+	if (libusb_claim_interface(devh, itfnum) < 0) {
+		debug("Can't claim interface %d", itfnum);
+		goto bail;
+	}
+
+	device_bdaddr = get_bdaddr(devh, itfnum);
+	if (device_bdaddr == NULL) {
+		debug("Failed to get the Bluetooth address from the device");
+		goto bail;
+	}
+
+	device = create_cable_association(conn,
+					  adapter,
+					  "PLAYSTATION(R)3 Controller",
+					  device_bdaddr,
+					  VENDOR, PRODUCT, SIXAXIS_PNP_RECORD);
+	btd_device_add_uuid(device, HID_UUID);
+
+	adapter_get_address(adapter, &dst);
+	ba2str(&dst, adapter_bdaddr);
+	debug("Adapter bdaddr %s", adapter_bdaddr);
+
+	if (set_master_bdaddr(devh, itfnum, adapter_bdaddr) == FALSE) {
+		debug("Failed to set the master Bluetooth address");
+		goto bail;
+	}
+
+bail:
+	dbus_connection_unref(conn);
+	g_free(device_bdaddr);
+	libusb_release_interface(devh, itfnum);
+	/* We ignore errors from the reattach, as there's nothing we
+	 * can do about it */
+	libusb_attach_kernel_driver(devh, itfnum);
+	if (devh != NULL)
+		libusb_close(devh);
+}
+
+static void handle_device_plug(GUdevDevice *device)
+{
+	struct btd_adapter *adapter;
+	int adapter_id;
+	guint i;
+
+	libusb_device **list, *usbdev;
+	ssize_t num_devices;
+	struct libusb_device_descriptor desc;
+	guint8 j;
+
+	if (g_udev_device_has_property(device, "ID_SERIAL") == FALSE ||
+	    g_strcmp0(g_udev_device_get_property(device, "ID_SERIAL"), "Sony_PLAYSTATION_R_3_Controller") != 0)
+		return;
+	/* Don't look at events with an associated driver */
+	if (g_udev_device_has_property(device, "ID_USB_DRIVER") != FALSE)
+		return;
+
+	debug("Found Sixaxis device");
+
+	/* Look for the default adapter */
+	adapter_id = manager_get_default_adapter();
+	if (adapter_id == -1) {
+		debug("No adapters, exiting");
+		return;
+	}
+	adapter = manager_find_adapter_by_id(adapter_id);
+	if (adapter == NULL)
+		return;
+
+	/* Look for the USB device */
+	libusb_init(NULL);
+
+	num_devices = libusb_get_device_list(NULL, &list);
+	if (num_devices < 0) {
+		debug("libusb_get_device_list failed");
+		return;
+	}
+
+	usbdev = NULL;
+	for (i = 0; i < num_devices; i++) {
+		char *path;
+
+		path = g_strdup_printf("%s/%03d/%03d", "/dev/bus/usb",
+				       libusb_get_bus_number(list[i]),
+				       libusb_get_device_address(list[i]));
+		if (g_strcmp0(path, g_udev_device_get_device_file(device)) == 0) {
+			g_free(path);
+			usbdev = libusb_ref_device(list[i]);
+			break;
+		}
+		g_free(path);
+	}
+
+	libusb_free_device_list(list, TRUE);
+	if (usbdev == NULL) {
+		debug("Found a Sixaxis, but couldn't find it via libusb");
+		goto out;
+	}
+
+	if (libusb_get_device_descriptor(usbdev, &desc) < 0) {
+		debug("libusb_get_device_descriptor() failed");
+		goto out;
+	}
+
+	/* Look for the interface number that interests us */
+	for (j = 0; j < desc.bNumConfigurations; j++) {
+		struct libusb_config_descriptor *config;
+		guint8 k;
+
+		if (libusb_get_config_descriptor(usbdev, j, &config) < 0) {
+			debug("Failed to get config descriptor %d", j);
+			continue;
+		}
+
+		for (k = 0; k < config->bNumInterfaces; k++) {
+			const struct libusb_interface *itf = &config->interface[k];
+			int l;
+
+			for (l = 0; l < itf->num_altsetting ; l++) {
+				struct libusb_interface_descriptor alt;
+
+				alt = itf->altsetting[l];
+				if (alt.bInterfaceClass == 3) {
+					handle_usb_device(adapter, usbdev, config, l, &alt);
+				}
+			}
+		}
+	}
+
+out:
+	if (usbdev != NULL)
+		libusb_unref_device(usbdev);
+	libusb_exit(NULL);
+}
+
+static gboolean device_event_idle(GUdevDevice *device)
+{
+	handle_device_plug(device);
+	return FALSE;
+}
+
+static void device_event_cb(GUdevClient  *client,
+			    const char    *action,
+			    GUdevDevice  *device,
+			    gpointer       user_data)
+{
+	if (g_strcmp0(action, "add") == 0) {
+		/* FIXME:
+		 * This happens because we need to wait for the
+		 * device node to be created by udev,
+		 * we should really just call: handle_device_plug(device); */
+		g_object_ref(device);
+		g_timeout_add_seconds(1, (GSourceFunc) device_event_idle, device);
+	}
+}
+
+GUdevClient *client = NULL;
+
+static int cable_init(void)
+{
+	const char * subsystems[] = { "usb", NULL };
+
+	debug("Setup cable plugin");
+
+	g_type_init();
+
+	client = g_udev_client_new(subsystems);
+
+	/* Listen for newly connected devices */
+	g_signal_connect(G_OBJECT(client),
+			 "device-event",
+			 G_CALLBACK(device_event_cb),
+			 NULL);
+
+	return 0;
+}
+
+static void cable_exit(void)
+{
+	debug("Cleanup cable plugin");
+
+	if (client != NULL) {
+		g_object_unref(client);
+		client = NULL;
+	}
+}
+
+BLUETOOTH_PLUGIN_DEFINE(cable, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, cable_init, cable_exit)
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-04  9:28 [PATCH] Add sixaxis cable-pairing plugin Bastien Nocera
@ 2009-06-04 18:13 ` Marcel Holtmann
  2009-06-05 10:42   ` Bastien Nocera
  0 siblings, 1 reply; 13+ messages in thread
From: Marcel Holtmann @ 2009-06-04 18:13 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: BlueZ development

Hi Bastien,

> Works for me, comments welcome.
> 
> It uses gudev. See http://blog.fubar.dk/?p=106

no way. Please use just plain libudev and spare use the GObject
overhead. I have used libudev before and it is just fine. Not that I
have actually looked at your patch at all.

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-04 18:13 ` Marcel Holtmann
@ 2009-06-05 10:42   ` Bastien Nocera
  2009-06-05 13:06     ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-06-05 10:42 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: BlueZ development

On Thu, 2009-06-04 at 20:13 +0200, Marcel Holtmann wrote:
> Hi Bastien,
> 
> > Works for me, comments welcome.
> > 
> > It uses gudev. See http://blog.fubar.dk/?p=106
> 
> no way. Please use just plain libudev and spare use the GObject
> overhead. I have used libudev before and it is just fine. Not that I
> have actually looked at your patch at all.

GObject overhead? Did you intend on building sixaxis support into a 5
year old phone that it would actually matter?

Anyway, that'll go way down my list of things to do, along with porting
the rest of the apps to libusb1, which I guess will be a problem as
well.

gudev lives in udev-extras, and udev-extras will most likely be merged
into udev itself. And it saves me from reinventing the wheel, and doing
my own mainloop integration (etc.).

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 10:42   ` Bastien Nocera
@ 2009-06-05 13:06     ` Marcel Holtmann
  2009-06-05 13:52       ` Bastien Nocera
  0 siblings, 1 reply; 13+ messages in thread
From: Marcel Holtmann @ 2009-06-05 13:06 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: BlueZ development

Hi Bastien,

> > > Works for me, comments welcome.
> > > 
> > > It uses gudev. See http://blog.fubar.dk/?p=106
> > 
> > no way. Please use just plain libudev and spare use the GObject
> > overhead. I have used libudev before and it is just fine. Not that I
> > have actually looked at your patch at all.
> 
> GObject overhead? Did you intend on building sixaxis support into a 5
> year old phone that it would actually matter?

as I said, I am not adding a dependency on a GObject based library to
it. We wanna be able to replace GLib with eglib or similar if we have
to. Doing this for GObject based libraries is a pain in the ass. It is
just bloat.

> Anyway, that'll go way down my list of things to do, along with porting
> the rest of the apps to libusb1, which I guess will be a problem as
> well.

My biggest problem with libusb1 is that not all distros have it right
now. However that might change in 2 or 3 month. So it should become
easier.

> gudev lives in udev-extras, and udev-extras will most likely be merged
> into udev itself. And it saves me from reinventing the wheel, and doing
> my own mainloop integration (etc.).

The whole point of udev and udev-extras is to keep the dependency chain
small. So I don't think it gets merged.

The GLib mainloop integration for libudev is really simple. So that is
not an excuse for being lazy and dragging GObject into the mix.

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 13:06     ` Marcel Holtmann
@ 2009-06-05 13:52       ` Bastien Nocera
  2009-06-05 14:15         ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-06-05 13:52 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: BlueZ development

On Fri, 2009-06-05 at 15:06 +0200, Marcel Holtmann wrote:
> Hi Bastien,
> 
> > > > Works for me, comments welcome.
> > > > 
> > > > It uses gudev. See http://blog.fubar.dk/?p=106
> > > 
> > > no way. Please use just plain libudev and spare use the GObject
> > > overhead. I have used libudev before and it is just fine. Not that I
> > > have actually looked at your patch at all.
> > 
> > GObject overhead? Did you intend on building sixaxis support into a 5
> > year old phone that it would actually matter?
> 
> as I said, I am not adding a dependency on a GObject based library to
> it. We wanna be able to replace GLib with eglib or similar if we have
> to. Doing this for GObject based libraries is a pain in the ass. It is
> just bloat.

Which is exactly why the cable pairing stuff is implemented as a plugin.
You don't have to care about what's in it, or what its dependencies are
if you don't ship the plugin.

> > Anyway, that'll go way down my list of things to do, along with porting
> > the rest of the apps to libusb1, which I guess will be a problem as
> > well.
> 
> My biggest problem with libusb1 is that not all distros have it right
> now. However that might change in 2 or 3 month. So it should become
> easier.

That's not what the mail archives or IRC will tell me. Your problem was
that this would make bluez depend on 2 different libusb versions, which
you didn't want. That hasn't changed.

> > gudev lives in udev-extras, and udev-extras will most likely be merged
> > into udev itself. And it saves me from reinventing the wheel, and doing
> > my own mainloop integration (etc.).
> 
> The whole point of udev and udev-extras is to keep the dependency chain
> small. So I don't think it gets merged.
> 
> The GLib mainloop integration for libudev is really simple. So that is
> not an excuse for being lazy and dragging GObject into the mix.

You can keep personal attacks out of that. I think I've shown enough
patience trying to get this functionality into bluez proper.

I won't be updating this patch, but Luiz showed interested. My patch
will show up in the Fedora packages shortly.

Cheers

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 13:52       ` Bastien Nocera
@ 2009-06-05 14:15         ` Marcel Holtmann
  2009-06-05 14:48           ` Bastien Nocera
  0 siblings, 1 reply; 13+ messages in thread
From: Marcel Holtmann @ 2009-06-05 14:15 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: BlueZ development

Hi Bastien,

> > > > > Works for me, comments welcome.
> > > > > 
> > > > > It uses gudev. See http://blog.fubar.dk/?p=106
> > > > 
> > > > no way. Please use just plain libudev and spare use the GObject
> > > > overhead. I have used libudev before and it is just fine. Not that I
> > > > have actually looked at your patch at all.
> > > 
> > > GObject overhead? Did you intend on building sixaxis support into a 5
> > > year old phone that it would actually matter?
> > 
> > as I said, I am not adding a dependency on a GObject based library to
> > it. We wanna be able to replace GLib with eglib or similar if we have
> > to. Doing this for GObject based libraries is a pain in the ass. It is
> > just bloat.
> 
> Which is exactly why the cable pairing stuff is implemented as a plugin.
> You don't have to care about what's in it, or what its dependencies are
> if you don't ship the plugin.

then make it an external plugin in its own repository, but I am not
merging code that depends on anything GObject if it is just pointless
dependency and bloat.

> > > Anyway, that'll go way down my list of things to do, along with porting
> > > the rest of the apps to libusb1, which I guess will be a problem as
> > > well.
> > 
> > My biggest problem with libusb1 is that not all distros have it right
> > now. However that might change in 2 or 3 month. So it should become
> > easier.
> 
> That's not what the mail archives or IRC will tell me. Your problem was
> that this would make bluez depend on 2 different libusb versions, which
> you didn't want. That hasn't changed.

My answer might be misleading here. My view on this one hasn't changed.
I want either libusb0 or libusb1. However libusb1 becomes only an option
when all major distros did a refresh and have it available. So meaning
BlueZ will be ported over to libusb1 completely at some point. The point
is closer now than 6 month ago.

> > > gudev lives in udev-extras, and udev-extras will most likely be merged
> > > into udev itself. And it saves me from reinventing the wheel, and doing
> > > my own mainloop integration (etc.).
> > 
> > The whole point of udev and udev-extras is to keep the dependency chain
> > small. So I don't think it gets merged.
> > 
> > The GLib mainloop integration for libudev is really simple. So that is
> > not an excuse for being lazy and dragging GObject into the mix.
> 
> You can keep personal attacks out of that. I think I've shown enough
> patience trying to get this functionality into bluez proper.

This is not personal. I am keeping a watch on the dependencies of BlueZ
and I don't see any need for adding GObject to the mix for the SixAxis
support. Feel free to convince me that GObject based gudev is really
necessary for this. Until then I declare this bloat.

Please remember that BlueZ will run on embedded devices with limited
memory and space requirements. You might argue that these devices don't
need SixAxis support, but I prefer to keep that option.

> I won't be updating this patch, but Luiz showed interested. My patch
> will show up in the Fedora packages shortly.

That is your choice. Personally I really dislike if distros just go
against upstream and start merging stuff, because it takes more effort
to get it into upstream first.

On that point, you haven't merged the Socket fix upstream and also the
Wacom and UTF-8 fix could be send upstream. I know you send some version
of these at least once or twice, but besides me also Johan could merge
these patches.

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 14:15         ` Marcel Holtmann
@ 2009-06-05 14:48           ` Bastien Nocera
  2009-06-05 14:56             ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-06-05 14:48 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: BlueZ development

On Fri, 2009-06-05 at 16:15 +0200, Marcel Holtmann wrote:
> 
> > You can keep personal attacks out of that. I think I've shown enough
> > patience trying to get this functionality into bluez proper.
> 
> This is not personal. I am keeping a watch on the dependencies of
> BlueZ
> and I don't see any need for adding GObject to the mix for the SixAxis
> support. Feel free to convince me that GObject based gudev is really
> necessary for this. Until then I declare this bloat.

No, it's not absolutely necessary, but somebody has to reinvent the
wheel, and I'm not happy spending time doing that.

> Please remember that BlueZ will run on embedded devices with limited
> memory and space requirements. You might argue that these devices
> don't
> need SixAxis support, but I prefer to keep that option.

Yes. And if such uses exist, I'm sure they'd be happy putting some
effort into bluez and do the port from gudev to libudev themselves.

> > I won't be updating this patch, but Luiz showed interested. My patch
> > will show up in the Fedora packages shortly.
> 
> That is your choice. Personally I really dislike if distros just go
> against upstream and start merging stuff, because it takes more effort
> to get it into upstream first.

All my patches are sent upstream before they go into the packages, and I
think I put quite a bit of work into this. But at the end of the day, I
only have so much time, and rewriting bits of code because the upstream
doesn't like GObject isn't what I call a good use of my time. So I'm
leaving it to somebody else to go the last mile because I can't be
bothered.

> On that point, you haven't merged the Socket fix upstream

It's not upstreamable, see the RH bugzilla. It depends on a kernel patch
that can't go upstream.

>  and also the
> Wacom and UTF-8 fix could be send upstream.

They already have, and you commented on them. I still believe the UTF-8
one could be merged as-is, but I don't have a good answer for the Wacom
one, which would need more investigation.

>  I know you send some version
> of these at least once or twice, but besides me also Johan could merge
> these patches.

Cheers

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 14:48           ` Bastien Nocera
@ 2009-06-05 14:56             ` Marcel Holtmann
  2009-06-05 15:06               ` Bastien Nocera
  0 siblings, 1 reply; 13+ messages in thread
From: Marcel Holtmann @ 2009-06-05 14:56 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: BlueZ development

Hi Bastien,

> > > You can keep personal attacks out of that. I think I've shown enough
> > > patience trying to get this functionality into bluez proper.
> > 
> > This is not personal. I am keeping a watch on the dependencies of
> > BlueZ
> > and I don't see any need for adding GObject to the mix for the SixAxis
> > support. Feel free to convince me that GObject based gudev is really
> > necessary for this. Until then I declare this bloat.
> 
> No, it's not absolutely necessary, but somebody has to reinvent the
> wheel, and I'm not happy spending time doing that.
> 
> > Please remember that BlueZ will run on embedded devices with limited
> > memory and space requirements. You might argue that these devices
> > don't
> > need SixAxis support, but I prefer to keep that option.
> 
> Yes. And if such uses exist, I'm sure they'd be happy putting some
> effort into bluez and do the port from gudev to libudev themselves.
> 
> > > I won't be updating this patch, but Luiz showed interested. My patch
> > > will show up in the Fedora packages shortly.
> > 
> > That is your choice. Personally I really dislike if distros just go
> > against upstream and start merging stuff, because it takes more effort
> > to get it into upstream first.
> 
> All my patches are sent upstream before they go into the packages, and I
> think I put quite a bit of work into this. But at the end of the day, I
> only have so much time, and rewriting bits of code because the upstream
> doesn't like GObject isn't what I call a good use of my time. So I'm
> leaving it to somebody else to go the last mile because I can't be
> bothered.

fair enough and if Luiz takes care of this I am more than happy either
way.

> > On that point, you haven't merged the Socket fix upstream
> 
> It's not upstreamable, see the RH bugzilla. It depends on a kernel patch
> that can't go upstream.

Which bug is it. What is missing and why haven't I seen that kernel
patch at least send to the mailing list for review.

> >  and also the
> > Wacom and UTF-8 fix could be send upstream.
> 
> They already have, and you commented on them. I still believe the UTF-8
> one could be merged as-is, but I don't have a good answer for the Wacom
> one, which would need more investigation.

The UTF-8 might go in as is. As I said, Johan could review these and
merge them as good as I can. So feel free to bug him about it.

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 14:56             ` Marcel Holtmann
@ 2009-06-05 15:06               ` Bastien Nocera
  2009-06-06 17:41                 ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-06-05 15:06 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: BlueZ development

On Fri, 2009-06-05 at 16:56 +0200, Marcel Holtmann wrote:
> 
> > > On that point, you haven't merged the Socket fix upstream
> > 
> > It's not upstreamable, see the RH bugzilla. It depends on a kernel
> patch
> > that can't go upstream.
> 
> Which bug is it.

It's listed in the spec file, in the same directory you found that
patch:
https://bugzilla.redhat.com/show_bug.cgi?id=498756

>  What is missing and why haven't I seen that kernel
> patch at least send to the mailing list for review.

It's a patch to serial core, not Bluetooth, and there's a 3-year old
discussion on LKML, amongst other things.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-05 15:06               ` Bastien Nocera
@ 2009-06-06 17:41                 ` Luiz Augusto von Dentz
  2009-06-06 17:51                   ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2009-06-06 17:41 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: Marcel Holtmann, BlueZ development

Hi,

First I would like to know if splitting the current code of gudev into
udev-glib and udev-gobject would be a good idea to begin with. By
looking at connmand code it seems quite simple to integrate glib
mainloop with udev so if we were not adding any API to udev-glib it
seems like an unnecessary step, I heard that udev has some race
conditions so perhaps we could add some very basic watch registration
like we have done to libgdus. That way udev-object API doesn't have to
change much just depend on udev-glib.

On bluetoothd side, I would like to make udev code generic enough to
detect any bluetooth device not only sixaxis so we can do different
plugins to handle any device doing this cable association/cable
pairing thing.

--=20
Luiz Augusto von Dentz
Engenheiro de Computa=E7=E3o

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-06-06 17:41                 ` Luiz Augusto von Dentz
@ 2009-06-06 17:51                   ` Marcel Holtmann
  0 siblings, 0 replies; 13+ messages in thread
From: Marcel Holtmann @ 2009-06-06 17:51 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Bastien Nocera, BlueZ development

Hi Luiz,

> First I would like to know if splitting the current code of gudev into
> udev-glib and udev-gobject would be a good idea to begin with. By
> looking at connmand code it seems quite simple to integrate glib
> mainloop with udev so if we were not adding any API to udev-glib it
> seems like an unnecessary step, I heard that udev has some race
> conditions so perhaps we could add some very basic watch registration
> like we have done to libgdus. That way udev-object API doesn't have to
> change much just depend on udev-glib.
> 
> On bluetoothd side, I would like to make udev code generic enough to
> detect any bluetooth device not only sixaxis so we can do different
> plugins to handle any device doing this cable association/cable
> pairing thing.

don't bother with udev-glib here. The native libudev integration with
mainloop is simple enough. If you need an example, look at ConnMan.

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] Add sixaxis cable-pairing plugin
  2009-10-09 13:19 Bastien Nocera
@ 2009-10-11  9:40 ` Marcel Holtmann
  0 siblings, 0 replies; 13+ messages in thread
From: Marcel Holtmann @ 2009-10-11  9:40 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: BlueZ development

Hi Bastien,

> Implement the old "sixpair" using libudev and libusb-1.0.
> 
> When a Sixaxis device is plugged in, events are filtered, and
> the device is selected, poked around to set the default Bluetooth
> address, and added to the database of the current default adapter.
> ---
>  Makefile.am     |    9 +-
>  acinclude.m4    |   16 +++
>  configure.ac    |    1 +
>  plugins/cable.c |  384
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 408 insertions(+), 2 deletions(-)
>  create mode 100644 plugins/cable.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index c8337d6..e5eccdf 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -162,6 +162,11 @@ builtin_modules += service
>  builtin_sources += plugins/service.c
>  endif
>  
> +if CABLE
> +builtin_modules += cable
> +builtin_sources += plugins/cable.c
> +endif
> +

since it is not really a generic cable pairing. I prefer that we just
call this SIXPAIR and sixpair.c

>  builtin_modules += hciops
>  builtin_sources += plugins/hciops.c
>  
> @@ -192,7 +197,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources)
> $(builtin_sources) \
>                         src/dbus-common.c src/dbus-common.h \
>                         src/dbus-hci.h src/dbus-hci.c
>  src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
> -                                                       @CAPNG_LIBS@
> -ldl
> +                                                       @CAPNG_LIBS@
> @CABLE_LIBS@ -ldl
>  src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
>                                         -Wl,--version-script=src/bluetooth.ver
>  src_bluetoothd_DEPENDENCIES = src/bluetooth.ver lib/libbluetooth.la
> @@ -305,7 +310,7 @@ EXTRA_DIST += doc/manager-api.txt \
>  
>  AM_YFLAGS = -d
>  
> -AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
> +AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ @CABLE_CFLAGS@
> \
>                 -DBLUETOOTH_PLUGIN_BUILTIN -DPLUGINDIR=
> \""$(plugindir)"\"

This needs changing. I wanna have a separate udev and libusb1 check.
However I can do that for you in case there are problems.
 
>  INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
> diff --git a/acinclude.m4 b/acinclude.m4
> index e7d1c32..10e5241 100644
> --- a/acinclude.m4
> +++ b/acinclude.m4
> @@ -142,6 +142,12 @@ AC_DEFUN([AC_PATH_USB], [
>                         [Define to 1 if you need the
> usb_interrupt_read() function.]))
>  ])
>  
> +AC_DEFUN([AC_PATH_CABLE], [
> +       PKG_CHECK_MODULES(CABLE, libudev libusb-1.0, cable_found=yes,
> cable_found=no)
> +       AC_SUBST(CABLE_CFLAGS)
> +       AC_SUBST(CABLE_LIBS)
> +])
> +
>  AC_DEFUN([AC_PATH_NETLINK], [
>         PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes,
> netlink_found=no)
>         AC_SUBST(NETLINK_CFLAGS)
> @@ -170,6 +176,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
>         netlink_enable=no
>         hal_enable=${hal_found}
>         usb_enable=${usb_found}
> +       cable_enable=${cable_found}
>         alsa_enable=${alsa_found}
>         gstreamer_enable=${gstreamer_found}
>         audio_enable=yes
> @@ -239,6 +246,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
>                 usb_enable=${enableval}
>         ])
>  
> +       AC_ARG_ENABLE(cable, AC_HELP_STRING([--enable-cable], [enable
> DeviceKit support]), [
> +               cable_enable=${enableval}
> +       ])
> +
>         AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink],
> [enable NETLINK support]), [
>                 netlink_enable=${enableval}
>         ])
> @@ -326,6 +337,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
>                 AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have
> capabilities library.])
>         fi
>  
> +       if (test "${cable_enable}" = "yes" && test "${cable_found}" =
> "yes"); then
> +               AC_DEFINE(HAVE_CABLE, 1, [Define to 1 if you have
> libcable.])
> +       fi
> +
>         AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" &&
> test "${sndfile_found}" = "yes")
>         AM_CONDITIONAL(NETLINK, test "${netlink_enable}" = "yes" &&
> test "${netlink_found}" = "yes")
>         AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test
> "${usb_found}" = "yes")
> @@ -350,4 +365,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
>         AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" &&
> test "${usb_found}" = "yes")
>         AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
>         AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" =
> "yes")
> +       AM_CONDITIONAL(CABLE, test "${cable_enable}" = "yes" && test
> "${cable_found}" = "yes")
>  ])
> diff --git a/configure.ac b/configure.ac
> index b93cca0..5df134f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -40,6 +40,7 @@ AC_PATH_GLIB
>  AC_PATH_ALSA
>  AC_PATH_GSTREAMER
>  AC_PATH_USB
> +AC_PATH_CABLE
>  AC_PATH_NETLINK
>  AC_PATH_SNDFILE
>  AC_PATH_CAPNG
> diff --git a/plugins/cable.c b/plugins/cable.c
> new file mode 100644
> index 0000000..0b7cc7a
> --- /dev/null
> +++ b/plugins/cable.c
> @@ -0,0 +1,384 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2009  Bastien Nocera <hadess@hadess.net>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> modify
> + *  it under the terms of the GNU General Public License as published
> by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> 02110-1301  USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <glib.h>
> +#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
> +#include <libudev.h>
> +#include <dbus/dbus.h>
> +#include <bluetooth/bluetooth.h>
> +#include <bluetooth/sdp.h>
> +#include <libusb.h>
> +
> +#include "plugin.h"
> +#include "logging.h"
> +
> +#include "manager.h"
> +#include "adapter.h"
> +#include "device.h"
> +
> +#include "storage.h"
> +#include "sdp_lib.h"
> +
> +/* Vendor and product ID for the Sixaxis PS3 controller */
> +#define VENDOR 0x054c
> +#define PRODUCT 0x0268
> +#define SIXAXIS_PNP_RECORD
> "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
> +#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
> +
> +static struct btd_device *create_cable_association(DBusConnection
> *conn,
> +                                                   struct btd_adapter
> *adapter,
> +                                                   const char *name,
> +                                                   const char
> *address,
> +                                                   guint32 vendor_id,
> +                                                   guint32
> product_id,
> +                                                   const char
> *pnp_record)
> +{
> +       sdp_record_t *rec;
> +       struct btd_device *device;
> +       bdaddr_t src, dst;
> +       char srcaddr[18];
> +
> +       device = adapter_find_device(adapter, address);
> +       if (device == NULL)
> +               device = adapter_create_device(conn, adapter,
> address);
> +       if (device != NULL) {
> +               device_set_temporary(device, FALSE);
> +               device_set_name(device, name);
> +       }
> +
> +       str2ba(address, &dst);
> +       adapter_get_address(adapter, &src);
> +       ba2str(&src, srcaddr);
> +
> +       write_device_name(&dst, &src, (char *) name);
> +
> +       /* Store the device's SDP record */
> +       rec = record_from_string(pnp_record);
> +       store_record(srcaddr, address, rec);
> +       sdp_record_free(rec);
> +       /* Set the device id */
> +       store_device_id(srcaddr, address, 0xffff, vendor_id,
> product_id, 0);
> +       /* Don't write a profile, it will be updated when the device
> connects */
> +
> +       write_trust(srcaddr, address, "[all]", TRUE);
> +
> +       return device;
> +}
> +
> +static char *get_bdaddr(libusb_device_handle *devh, int itfnum)
> +{
> +       unsigned char msg[17];
> +       char *address;
> +       int res;
> +
> +       res = libusb_control_transfer(devh,
> +                                     LIBUSB_ENDPOINT_IN |
> LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
> +                                     0x01, 0x03f2, itfnum,
> +                                     (void*) msg, sizeof(msg),
> +                                     5000);
> +
> +       if (res < 0) {
> +               debug("Getting the device Bluetooth address failed");
> +               return NULL;
> +       }
> +
> +       address = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
> +                                 msg[4], msg[5], msg[6], msg[7],
> msg[8], msg[9]);
> +
> +       debug("Device Bluetooth address: %s\n", address);
> +
> +       return address;
> +}
> +
> +static gboolean set_master_bdaddr(libusb_device_handle *devh, int
> itfnum, char *host)
> +{
> +       unsigned char msg[8];
> +       int mac[6];
> +       int res;
> +
> +       if (sscanf(host, "%X:%X:%X:%X:%X:%X",
> +                  &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) !=
> 6) {
> +               return FALSE;
> +       }
> +
> +       msg[0] = 0x01;
> +       msg[1] = 0x00;
> +       msg[2] = mac[0];
> +       msg[3] = mac[1];
> +       msg[4] = mac[2];
> +       msg[5] = mac[3];
> +       msg[6] = mac[4];
> +       msg[7] = mac[5];
> +
> +       res = libusb_control_transfer(devh,
> +                                     LIBUSB_ENDPOINT_OUT |
> LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
> +                                     0x09, 0x03f5, itfnum,
> +                                     (void*) msg, sizeof(msg),
> +                                     5000);
> +
> +       if (res < 0) {
> +               debug("Setting the master Bluetooth address failed");
> +               return FALSE;
> +       }
> +
> +       return TRUE;
> +}

These are all blocking functions. That worries me a little bit in case
we have weird timeouts. I know that libusb1 supports async operation. Is
it possible to use that?

> +static void handle_usb_device(struct btd_adapter *adapter,
> +                             libusb_device *dev,
> +                             struct libusb_config_descriptor *cfg,
> +                             int itfnum,
> +                             const struct libusb_interface_descriptor
> *alt)
> +{
> +       DBusConnection *conn;
> +       libusb_device_handle *devh;
> +       char *device_bdaddr;
> +       char adapter_bdaddr[18];
> +       struct btd_device *device;
> +       bdaddr_t dst;
> +
> +       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
> +       if (conn == NULL) {
> +               debug("Failed to get on the bus");
> +               return;
> +       }
> +
> +       if (libusb_open(dev, &devh) < 0) {
> +               debug("Can't open device");
> +               goto bail;
> +       }
> +       libusb_detach_kernel_driver(devh, itfnum);
> +
> +       if (libusb_claim_interface(devh, itfnum) < 0) {
> +               debug("Can't claim interface %d", itfnum);
> +               goto bail;
> +       }
> +
> +       device_bdaddr = get_bdaddr(devh, itfnum);
> +       if (device_bdaddr == NULL) {
> +               debug("Failed to get the Bluetooth address from the
> device");
> +               goto bail;
> +       }
> +
> +       device = create_cable_association(conn,
> +                                         adapter,
> +                                         "PLAYSTATION(R)3
> Controller",
> +                                         device_bdaddr,
> +                                         VENDOR, PRODUCT,
> SIXAXIS_PNP_RECORD);
> +       btd_device_add_uuid(device, HID_UUID);
> +
> +       adapter_get_address(adapter, &dst);
> +       ba2str(&dst, adapter_bdaddr);
> +       debug("Adapter bdaddr %s", adapter_bdaddr);
> +
> +       if (set_master_bdaddr(devh, itfnum, adapter_bdaddr) == FALSE)
> {
> +               debug("Failed to set the master Bluetooth address");
> +               goto bail;
> +       }
> +
> +bail:
> +       dbus_connection_unref(conn);
> +       g_free(device_bdaddr);
> +       libusb_release_interface(devh, itfnum);
> +       /* We ignore errors from the reattach, as there's nothing we
> +        * can do about it */
> +       libusb_attach_kernel_driver(devh, itfnum);
> +       if (devh != NULL)
> +               libusb_close(devh);
> +}

It has been a long time I looked through this stuff. So does the
controller user USB control messages or are they just plain HID message.
If HID, then I would prefer if we use hidraw and don't have to detach
the kernel driver.

> +
> +static void handle_device_plug(struct udev_device *udevice)
> +{
> +       struct btd_adapter *adapter;
> +       int adapter_id;
> +       guint i;
> +
> +       libusb_device **list, *usbdev;
> +       ssize_t num_devices;
> +       struct libusb_device_descriptor desc;
> +       guint8 j;
> +
> +       if (g_strcmp0(udev_device_get_property_value(udevice,
> "ID_SERIAL"),
> +                     "Sony_PLAYSTATION_R_3_Controller") != 0)
> +               return;
> +       /* Don't look at events with an associated driver */
> +       if (udev_device_get_property_value(udevice, "ID_USB_DRIVER") !
> = NULL)
> +               return;
> +
> +       debug("Found Sixaxis device");
> +
> +       /* Look for the default adapter */
> +       adapter_id = manager_get_default_adapter();
> +       if (adapter_id == -1) {
> +               debug("No adapters, exiting");
> +               return;
> +       }
> +       adapter = manager_find_adapter_by_id(adapter_id);
> +       if (adapter == NULL)
> +               return;
> +
> +       /* Look for the USB device */
> +       libusb_init(NULL);
> +
> +       num_devices = libusb_get_device_list(NULL, &list);
> +       if (num_devices < 0) {
> +               debug("libusb_get_device_list failed");
> +               return;
> +       }
> +
> +       usbdev = NULL;
> +       for (i = 0; i < num_devices; i++) {
> +               char *path;
> +
> +               path = g_strdup_printf("%s/%03d/%03d", "/dev/bus/usb",
> +                                      libusb_get_bus_number(list[i]),
> +
> libusb_get_device_address(list[i]));
> +               if (g_strcmp0(path, udev_device_get_devnode(udevice))
> == 0) {
> +                       g_free(path);
> +                       usbdev = libusb_ref_device(list[i]);
> +                       break;
> +               }
> +               g_free(path);
> +       }
> +
> +       libusb_free_device_list(list, TRUE);
> +       if (usbdev == NULL) {
> +               debug("Found a Sixaxis, but couldn't find it via
> libusb");
> +               goto out;
> +       }
> +
> +       if (libusb_get_device_descriptor(usbdev, &desc) < 0) {
> +               debug("libusb_get_device_descriptor() failed");
> +               goto out;
> +       }
> +
> +       /* Look for the interface number that interests us */
> +       for (j = 0; j < desc.bNumConfigurations; j++) {
> +               struct libusb_config_descriptor *config;
> +               guint8 k;
> +
> +               if (libusb_get_config_descriptor(usbdev, j, &config) <
> 0) {
> +                       debug("Failed to get config descriptor %d",
> j);
> +                       continue;
> +               }
> +
> +               for (k = 0; k < config->bNumInterfaces; k++) {
> +                       const struct libusb_interface *itf =
> &config->interface[k];
> +                       int l;
> +
> +                       for (l = 0; l < itf->num_altsetting ; l++) {
> +                               struct libusb_interface_descriptor
> alt;
> +
> +                               alt = itf->altsetting[l];
> +                               if (alt.bInterfaceClass == 3) {
> +                                       handle_usb_device(adapter,
> usbdev, config, l, &alt);
> +                               }
> +                       }
> +               }
> +       }
> +
> +out:
> +       if (usbdev != NULL)
> +               libusb_unref_device(usbdev);
> +       libusb_exit(NULL);
> +}

What we are missing from libusb1 is a function to create the device
handle directly from a udev syspath. The enumeration is actually pretty
bad since it wakes up all USB devices on the all busses.

> +
> +static gboolean device_event_idle(struct udev_device *udevice)
> +{
> +       handle_device_plug(udevice);
> +       udev_device_unref(udevice);
> +       return FALSE;
> +}
> +
> +static struct udev *ctx = NULL;
> +static struct udev_monitor *monitor = NULL;
> +static guint watch_id = 0;
> +
> +static gboolean
> +monitor_event(GIOChannel *source,
> +             GIOCondition condition,
> +             gpointer data)
> +{
> +       struct udev_device *udevice;
> +
> +       udevice = udev_monitor_receive_device(monitor);
> +       if (udevice == NULL)
> +               goto out;
> +       if (g_strcmp0(udev_device_get_action(udevice), "add") != 0)
> +               goto out;
> +
> +       g_timeout_add_seconds(1, (GSourceFunc) device_event_idle,
> udevice);
> +
> +out:
> +       return TRUE;
> +}

Why is the timeout thing needed? Or do you actually want idle callback?

Regards

Marcel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] Add sixaxis cable-pairing plugin
@ 2009-10-09 13:19 Bastien Nocera
  2009-10-11  9:40 ` Marcel Holtmann
  0 siblings, 1 reply; 13+ messages in thread
From: Bastien Nocera @ 2009-10-09 13:19 UTC (permalink / raw)
  To: BlueZ development

[-- Attachment #1: Type: text/plain, Size: 56 bytes --]

This time using libudev as opposed to libgudev.

Cheers

[-- Attachment #2: 0001-Add-sixaxis-cable-pairing-plugin.patch --]
[-- Type: text/x-patch, Size: 14788 bytes --]

>From 7194839445edb3fd112b2bc79878c303e3b7c9e2 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Tue, 1 Sep 2009 17:32:48 +0100
Subject: [PATCH] Add sixaxis cable-pairing plugin

Implement the old "sixpair" using libudev and libusb-1.0.

When a Sixaxis device is plugged in, events are filtered, and
the device is selected, poked around to set the default Bluetooth
address, and added to the database of the current default adapter.
---
 Makefile.am     |    9 +-
 acinclude.m4    |   16 +++
 configure.ac    |    1 +
 plugins/cable.c |  384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 408 insertions(+), 2 deletions(-)
 create mode 100644 plugins/cable.c

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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2009-10-11  9:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-04  9:28 [PATCH] Add sixaxis cable-pairing plugin Bastien Nocera
2009-06-04 18:13 ` Marcel Holtmann
2009-06-05 10:42   ` Bastien Nocera
2009-06-05 13:06     ` Marcel Holtmann
2009-06-05 13:52       ` Bastien Nocera
2009-06-05 14:15         ` Marcel Holtmann
2009-06-05 14:48           ` Bastien Nocera
2009-06-05 14:56             ` Marcel Holtmann
2009-06-05 15:06               ` Bastien Nocera
2009-06-06 17:41                 ` Luiz Augusto von Dentz
2009-06-06 17:51                   ` Marcel Holtmann
2009-10-09 13:19 Bastien Nocera
2009-10-11  9:40 ` Marcel Holtmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.