Skip to contentSkip to conversation

Add sixpair

PATCH In review Bastien Nocera 2 participants 8 messages Oct 15, 2008 – Feb 28, 2009 Bluetooth drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Add sixpair

Heya,

Here are the patches to get sixpair support built into BlueZ. It uses libusb-1.0 as well as a yet to be merged libusb-1.0 patch to allow re-attaching a driver to a device.

Problems left to solve:
- sixaxis enabler code (as seen in enable_sixaxis() in compat/hidd.c) seems to have disappeared from the input plugin. Is that done in the kernel now, or was it just removed?
- After "cable pairing" the device, I need to unplug/replug the adapter, or restart bluetoothd. Can anyone think of a better way of getting the list of devices updated?
- Some minor niggles in the code itself (use D-Bus instead of parsing command-line tools)
- udev rule(s) and parsing only the selected device would be necessary if not required

Cheers

Quoted 1 line

From c06f9fa3f7d088c173403d602209d7a18e7b00e5 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Sat, 11 Oct 2008 00:55:02 +0100
Subject: [PATCH] Add sixpair tool

Sixpair is an unfinished helper to automatically pair a plugged in Playstation 3 Sixaxis Bluetooth joypad.

---
 input/sixpair.c |  393 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 393 insertions(+), 0 deletions(-)
 create mode 100644 input/sixpair.c
input/sixpair.c new file +393 -0
new file mode 100644
index 0000000..818d283
@@ -0,0 +1,393 @@
+/* To compile
+ * gcc -g -Wall -I../src -I../lib/ -I../include -DSTORAGEDIR=\"/var/lib/bluetooth\" -o sixpair sixpair.c ../src/storage.c ../common/libhelper.a -I../common `pkg-config --libs --cflags glib-2.0 libusb` -lbluetooth
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <sdp.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hidp.h>
+#include <glib.h>
+#include <usb.h>
+
+#include "storage.h"
+
+/* Vendor and product ID for the Sixaxis PS3 controller */
+#define VENDOR 0x054c
+#define PRODUCT 0x0268
+
+#define USB_DIR_IN 0x80
+#define USB_DIR_OUT 0
+
+gboolean option_get_master = TRUE;
+char *option_master= NULL;
+gboolean option_store_info = TRUE;
+const char *option_device = NULL;
+gboolean option_quiet = FALSE;
+
+const GOptionEntry options[] = {
+	{ "get-master", '\0', 0, G_OPTION_ARG_NONE, &option_get_master, "Get currently set master address", NULL },
+	{ "set-master", '\0', 0, G_OPTION_ARG_STRING, &option_master, "Set master address (\"auto\" for automatic)", NULL },
+	{ "store-info", '\0', 0, G_OPTION_ARG_NONE, &option_store_info, "Store the HID info into the input database", NULL },
+	{ "device", '\0', 0, G_OPTION_ARG_STRING, &option_device, "Only handle one device (default, all supported", NULL },
+	{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet, "Quieten the output", NULL },
+	{ NULL }
+};
+
+static gboolean
+show_master (usb_dev_handle *devh, int itfnum)
+{
+	unsigned char msg[8];
+	int res;
+
+	res = usb_control_msg (devh,
+			       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			       0x01, 0x03f5, itfnum,
+			       (void*) msg, sizeof(msg),
+			       5000);
+
+	if (res < 0) {
+		g_warning ("Getting the master Bluetooth address failed");
+		return FALSE;
+	}
+	g_print ("Current Bluetooth master: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		 msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
+
+	return TRUE;
+}
+
+static char *
+get_bdaddr (usb_dev_handle *devh, int itfnum)
+{
+	unsigned char msg[17];
+	char *address;
+	int res;
+
+	res = usb_control_msg (devh,
+			       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			       0x01, 0x03f2, itfnum,
+			       (void*) msg, sizeof(msg),
+			       5000);
+
+	if (res < 0) {
+		g_warning ("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]);
+
+	if (option_quiet == FALSE) {
+		g_print ("Device Bluetooth address: %s\n", address);
+	}
+
+	return address;
+}
+
+static gboolean
+set_master_bdaddr (usb_dev_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 = usb_control_msg (devh,
+			       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			       0x09, 0x03f5, itfnum,
+			       (void*) msg, sizeof(msg),
+			       5000);
+
+	if (res < 0) {
+		g_warning ("Setting the master Bluetooth address failed");
+		return FALSE;
+	}
+
+	return TRUE;
+
+}
+
+static char *
+get_host_bdaddr (void)
+{
+	FILE *f;
+	int mac[6];
+
+	//FIXME use dbus to get the default adapter
+
+	f = popen("hcitool dev", "r");
+
+	if (f == NULL) {
+		//FIXME
+		return NULL;
+	}
+	if (fscanf(f, "%*s\n%*s %x:%x:%x:%x:%x:%x",
+		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
+		//FIXME
+		return NULL;
+	}
+
+	return g_strdup_printf ("%x:%x:%x:%x:%x:%x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int
+get_record_info (struct usb_interface_descriptor *alt, unsigned int *_len, unsigned int *_country, uint16_t *_version)
+{
+	unsigned char *buf;
+	unsigned int size, len, country;
+	uint16_t version;
+	int l;
+
+	len = 0;
+	country = 0;
+	version = 0;
+
+	if (!alt->extralen)
+		return 0;
+
+	size = alt->extralen;
+	buf = alt->extra;
+	while (size >= 2 * sizeof(u_int8_t)) {
+		if (buf[0] < 2 || buf[1] != USB_DT_HID)
+			continue;
+
+		//FIXME that should be "21"
+		//g_message ("country: %u", buf[4]);
+		//country = buf[4];
+		//country = 0x21;
+		country = 0;
+		version = (buf[3] << 8) + buf[2];
+
+		for (l = 0; l < buf[5]; l++) {
+			/* we are just interested in report descriptors*/
+			if (buf[6+3*l] != USB_DT_REPORT)
+				continue;
+			len = buf[7+3*l] | (buf[8+3*l] << 8);
+		}
+		size -= buf[0];
+		buf += buf[0];
+	}
+
+	if (len == 0)
+		return -1;
+	*_len = len;
+	*_country = country;
+	*_version = version;
+
+	return 0;
+}
+
+static void
+fill_req_from_usb (struct usb_device *dev, struct hidp_connadd_req *req, void *data, unsigned int len, unsigned int country, uint16_t version)
+{
+	req->vendor = dev->descriptor.idVendor;
+	req->product = dev->descriptor.idProduct;
+	req->version = version;
+	/* req->subclass already set */
+	req->country = country;
+	/* Default value */
+	req->parser = 0x0100;
+	/* What are we expecting here? No idea, but we don't seem to need it */
+	req->flags = 0;
+
+	req->rd_size = len;
+	req->rd_data = data;
+}
+
+static void
+store_info (const char *host, const char *device, struct hidp_connadd_req *req)
+{
+	bdaddr_t dest, src;
+
+	if (str2ba (host, &src) < 0) {
+		//FIXME
+		return;
+	}
+	if (str2ba (device, &dest) < 0) {
+		//FIXME
+		return;
+	}
+
+#if 0
+	if (store_device_info (&src, &dest, req) < 0)
+#endif
+		g_message ("store_device_info failed");
+}
+
+static int
+handle_device (struct usb_device *dev, struct usb_config_descriptor *cfg, int itfnum, struct usb_interface_descriptor *alt)
+{
+	usb_dev_handle *devh;
+	int res, retval;
+
+	retval = -1;
+
+	devh = usb_open (dev);
+	if (devh == NULL) {
+		g_warning ("Can't open device");
+		goto bail;
+	}
+	usb_detach_kernel_driver_np (devh, itfnum);
+
+	res = usb_claim_interface (devh, itfnum);
+	if (res < 0) {
+		g_warning ("Can't claim interface %d", itfnum);
+		goto bail;
+	}
+
+	if (option_get_master != FALSE) {
+		if (show_master (devh, itfnum) == FALSE)
+			goto bail;
+		retval = 0;
+	}
+
+	if (option_master != NULL) {
+		if (strcmp (option_master, "auto") == 0) {
+			g_free (option_master);
+			option_master = get_host_bdaddr ();
+			if (option_master == NULL) {
+				g_warning ("Can't get bdaddr from default device");
+				retval = -1;
+				goto bail;
+			}
+		}
+	} else {
+		option_master = get_host_bdaddr ();
+		if (option_master == NULL) {
+			g_warning ("Can't get bdaddr from default device");
+			retval = -1;
+			goto bail;
+		}
+	}
+
+	if (option_store_info != FALSE) {
+		unsigned char data[8192];
+		struct hidp_connadd_req req;
+		unsigned int len, country;
+		int n;
+		uint16_t version;
+		char *device;
+
+		device = get_bdaddr (devh, itfnum);
+		if (device == NULL) {
+			retval = -1;
+			goto bail;
+		}
+
+		if (get_record_info (alt, &len, &country, &version) < 0) {
+			g_warning ("Can't get record info");
+			retval = -1;
+			goto bail;
+		}
+
+		if ((n = usb_control_msg(devh,
+				    USB_ENDPOINT_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE,
+				    USB_REQ_GET_DESCRIPTOR,
+				    (USB_DT_REPORT << 8),
+				    itfnum, (void *) &data, len, 5000)) < 0) {
+			g_warning ("Can't get report descriptor (length: %d, interface: %d)", len, itfnum);
+			retval = -1;
+			goto bail;
+		}
+
+		req.subclass = alt->bInterfaceSubClass;
+		fill_req_from_usb (dev, &req, data, len, country, version);
+
+		store_info (option_master, device, &req);
+
+		if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
+			retval = -1;
+			goto bail;
+		}
+
+		//FIXME finally, set device as trusted
+	}
+
+bail:
+	if (devh != NULL)
+		usb_close (devh);
+
+	return retval;
+}
+
+int main (int argc, char **argv)
+{
+	GOptionContext *context;
+	GError *error = NULL;
+	struct usb_bus *busses, *bus;
+
+	context = g_option_context_new ("- Manage Sixaxis PS3 controllers");
+	g_option_context_add_main_entries (context, options, NULL);
+	if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
+		g_warning ("Couldn't parse command-line options: %s", error->message);
+		return 1;
+	}
+
+	/* Check that the passed bdaddr is correct */
+	if (option_master != NULL && strcmp (option_master, "auto") != 0) {
+		//FIXME check bdaddr
+	}
+
+	/* Find device(s) */
+	usb_init ();
+	if (usb_find_busses () < 0) {
+		g_warning ("usb_find_busses failed");
+		return 1;
+	}
+	if (usb_find_devices () < 0) {
+		g_warning ("usb_find_devices failed");
+		return 1;
+	}
+
+	busses = usb_get_busses();
+	if (busses == NULL) {
+		g_warning ("usb_get_busses failed");
+		return 1;
+	}
+
+	for (bus = busses; bus; bus = bus->next) {
+		struct usb_device *dev;
+
+		for (dev = bus->devices; dev; dev = dev->next) {
+			struct usb_config_descriptor *cfg;
+
+			/* Here we check for the supported devices */
+			if (dev->descriptor.idVendor != VENDOR || dev->descriptor.idProduct != PRODUCT)
+				continue;
+
+			/* Look for the interface number that interests us */
+			for (cfg = dev->config; cfg < dev->config + dev->descriptor.bNumConfigurations; ++cfg) {
+				int itfnum;
+
+				for (itfnum = 0; itfnum < cfg->bNumInterfaces; ++itfnum) {
+					struct usb_interface *itf = &cfg->interface[itfnum];
+					struct usb_interface_descriptor *alt;
+
+					for (alt = itf->altsetting; alt < itf->altsetting + itf->num_altsetting; ++alt) {
+						if (alt->bInterfaceClass == 3) {
+							handle_device (dev, cfg, itfnum, alt);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
Signature · 1 line
1.5.5.2
Quoted 1 line

From a08bf92d81cf0bd5201a5de18b313836726c2a7f Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Sat, 11 Oct 2008 23:34:34 +0100
Subject: [PATCH] Port sixpair to libusb 1.0

Port sixpair to libusb-1.0, as it allows us to re-attach the driver to the device after we're done.

---
 input/sixpair.c |  142 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 72 insertions(+), 70 deletions(-)
input/sixpair.c +72 -70

277 lines not on this page · raw message

Signature · 1 line
1.5.5.2
Quoted 1 line

From 4a45364efa67dc7c5546f180bc7b67d64186d24c Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 12:50:40 +0100
Subject: [PATCH] Fix setting the master address on the sixaxis

Direction for the USB command was wrong, also disable all the report code, so sixpair can run (minus saving device records)

---
 input/sixpair.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
input/sixpair.c +8 -4
index 07fa679..92aa5f7 100644
@@ -105,7 +105,7 @@ set_master_bdaddr (libusb_device_handle *devh, int itfnum, char *host)
 	msg[7] = mac[5];
 
 	res = libusb_control_transfer (devh,
-				       LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+				       LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
 				       0x09, 0x03f5, itfnum,
 				       (void*) msg, sizeof(msg),
 				       5000);
@@ -285,7 +285,7 @@ handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itf
 			retval = -1;
 			goto bail;
 		}
-
+#if 0
 		if (get_record_info (alt, &len, &country, &version) < 0) {
 			g_warning ("Can't get record info");
 			retval = -1;
@@ -306,7 +306,7 @@ handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itf
 		fill_req_from_usb (dev, &req, data, len, country, version);
 
 		store_info (option_master, device, &req);
-
+#endif
 		if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
 			retval = -1;
 			goto bail;
@@ -317,7 +317,11 @@ handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itf
 
 bail:
 	libusb_release_interface (devh, itfnum);
-	libusb_attach_kernel_driver(devh, itfnum);
+	res = libusb_attach_kernel_driver(devh, itfnum);
+	if (res < 0) {
+		//FIXME sometimes the kernel tells us ENOENT, but succeeds anyway...
+		g_warning ("Reattaching the driver failed: %d", res);
+	}
 	if (devh != NULL)
 		libusb_close (devh);
 
Signature · 1 line
1.5.5.2
Quoted 1 line

From 44c1f80129e2279246fff4e33fe7b2e89dc200a6 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:20:22 +0100
Subject: [PATCH] Export record_from_string() from the storage functions

Export record_from_string() from the storage functions, so it can be used to generate an sdp_record from a static string in sixpair.c

---
 src/storage.c |    2 +-
 src/storage.h |    1 +
 2 files changed, 2 insertions(+), 1 deletions(-)
src/storage.c +1 -1
index d99fb33..ac1ec5b 100644
@@ -771,7 +771,7 @@ int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec)
 	return err;
 }
 
-static sdp_record_t *record_from_string(const gchar *str)
+sdp_record_t *record_from_string(const gchar *str)
 {
 	sdp_record_t *rec;
 	int size, i, len;
src/storage.h +1 -0
index bff36a7..29f08d8 100644
@@ -57,6 +57,7 @@ GSList *list_trusts(bdaddr_t *local, const char *service);
 int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles);
 int delete_entry(bdaddr_t *src, const char *storage, const char *key);
 int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec);
+sdp_record_t *record_from_string(const gchar *str);
 sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle);
 int delete_record(const gchar *src, const gchar *dst, const uint32_t handle);
 sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst);
Signature · 1 line
1.5.5.2
Quoted 1 line

From c78d0dfeeda1208bad41686b51b0a815c372be95 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:25:13 +0100
Subject: [PATCH] Store every record information for the sixaxis controllers

Remove out-dated code to parse the HID input descriptor Make sure that all the Bluetooth addresses used are upper-case Add captured once SDP PNP record for the sixaxis controller Store device id, profile, and trust information about the device

---
 input/sixpair.c |  137 +++++++-----------------------------------------------
 1 files changed, 18 insertions(+), 119 deletions(-)
input/sixpair.c +18 -119

197 lines not on this page · raw message

Signature · 1 line
1.5.5.2
Quoted 1 line

From 48e9d01b184c9ff5a353dd6502847fb249d278c1 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:28:42 +0100
Subject: [PATCH] Save name for the sixaxis controller

The name won't be there until we connect otherwise

---
 input/sixpair.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
input/sixpair.c +1 -0
index 3a2bd32..5c58b9b 100644
@@ -206,6 +206,7 @@ handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itf
 		str2ba(option_master, &src);
 		str2ba(device, &dst);
 		write_device_profiles(&src, &dst, "");
+		write_device_name(&src, &dst, "PLAYSTATION(R)3 Controller");
 		sdp_record_free(rec);
 
 		if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
Signature · 1 line
1.5.5.2
Quoted 1 line

From c9b2d0599a6a1d30f96a0064a524a7f904faf1a0 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:47:28 +0100
Subject: [PATCH] Detect libusb 1.0 and enable it by default

Necessary for sixpair to compile

---
 acinclude.m4        |   15 +++++++++++++++
 bootstrap-configure |    1 +
 configure.ac        |    1 +
 3 files changed, 17 insertions(+), 0 deletions(-)
acinclude.m4 +15 -0
index 45dd909..0a8fdbb 100644
@@ -156,6 +156,12 @@ AC_DEFUN([AC_PATH_USB], [
 			[Define to 1 if you need the usb_interrupt_read() function.]))
 ])
 
+AC_DEFUN([AC_PATH_USB1], [
+	PKG_CHECK_MODULES(USB1, libusb-1.0, usb1_found=yes, usb1_found=no)
+	AC_SUBST(USB_CFLAGS)
+	AC_SUBST(USB_LIBS)
+])
+
 AC_DEFUN([AC_PATH_NETLINK], [
 	PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes, netlink_found=no)
 	AC_SUBST(NETLINK_CFLAGS)
@@ -238,6 +244,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		usb_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(usb1, AC_HELP_STRING([--enable-usb1], [enable libusb 1.0 support]), [
+		usb1_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
 		netlink_enable=${enableval}
 	])
@@ -321,6 +331,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
 	fi
 
+	if (test "${usb1_enable}" = "yes" && test "${usb1_found}" = "yes"); then
+		AC_DEFINE(HAVE_LIBUSB1, 1, [Define to 1 if you have libusb-1.0.])
+	fi
+
 	AC_SUBST([BLUEZ_CFLAGS], ['-I$(top_builddir)/include'])
 	AC_SUBST([BLUEZ_LIBS], ['$(top_builddir)/lib/libbluetooth.la'])
 
@@ -333,6 +347,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	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")
+	AM_CONDITIONAL(USB1, test "${usb1_enable}" = "yes" && test "${usb1_found}" = "yes")
 	AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes")
 	AM_CONDITIONAL(ALSA, test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes")
 	AM_CONDITIONAL(GSTREAMER, test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes")
bootstrap-configure +1 -0
index 7b07fe1..3b22dd5 100755
@@ -27,6 +27,7 @@ fi
 		--enable-dund \
 		--enable-test \
 		--enable-cups \
+		--enable-usb1 \
 		--disable-manpages \
 		--disable-configfiles \
 		--disable-initscripts \
configure.ac +1 -0
index 33b4583..f603223 100644
@@ -32,6 +32,7 @@ AC_PATH_GMODULE
 AC_PATH_ALSA
 AC_PATH_GSTREAMER
 AC_PATH_USB
+AC_PATH_USB1
 AC_PATH_NETLINK
 AC_PATH_SNDFILE
 
Signature · 1 line
1.5.5.2
Quoted 1 line

From 8c2c57718e32d4da5c49c8df38f5a48a1c105375 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:48:51 +0100
Subject: [PATCH] Separate storage functions into a library

The separate storage functions will be used by sixpair

---
 src/Makefile.am |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
src/Makefile.am +5 -1
index 2a353a4..d39d73d 100644
@@ -13,15 +13,19 @@ statedir = $(localstatedir)/lib/bluetooth
 state_DATA =
 endif
 
+noinst_LIBRARIES = libbtd-storage.a
+libbtd_storage_a_SOURCES = storage.h storage.c
+
 sbin_PROGRAMS = bluetoothd
 
 bluetoothd_SOURCES = main.c security.c hcid.h sdpd.h \
 	sdpd-server.c sdpd-request.c sdpd-service.c sdpd-database.c \
-	plugin.h plugin.c storage.h storage.c agent.h agent.c \
+	plugin.h plugin.c agent.h agent.c \
 	error.h error.c manager.h manager.c adapter.h adapter.c \
 	device.h device.c dbus-common.c dbus-common.h dbus-hci.h dbus-hci.c
 
 bluetoothd_LDADD = $(top_builddir)/common/libhelper.a \
+	$(builddir)/libbtd-storage.a \
 	@GDBUS_LIBS@ @GMODULE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 
 if MAINTAINER_MODE
Signature · 1 line
1.5.5.2
Quoted 1 line

From 444bfee09d378ac4e5fdd8c05b8bb01b8b57f418 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:49:58 +0100
Subject: [PATCH] Build sixpair through the build system

Using the libusb 1.0 libs as well as the separate storage library, compile sixpair without hacks

---
 input/Makefile.am |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)
input/Makefile.am +11 -2
index 1b3ab5d..59cf481 100644
@@ -8,14 +8,23 @@ input_la_SOURCES = main.c manager.h manager.c \
 		server.h server.c device.h device.c \
 		fakehid.c fakehid.h
 
-LDADD = $(top_builddir)/common/libhelper.a \
+input_la_LIBADD = $(top_builddir)/common/libhelper.a \
 		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+if USB1
+bin_PROGRAMS = sixpair
+sixpair_SOURCES = sixpair.c
+sixpair_LDADD = $(top_builddir)/src/libbtd-storage.a \
+		$(top_builddir)/common/libhelper.a \
+		@USB1_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@
+endif
+
 endif
 
 AM_LDFLAGS = -module -avoid-version -no-undefined \
 			-export-symbols-regex bluetooth_plugin_desc
 
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ @USB1_CFLAGS@
 
 INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
 
Signature · 1 line
1.5.5.2
Quoted 1 line

From b2c8fe5f5b1141284dce71a0345712cf16c1f665 Mon Sep 17 00:00:00 2001

From: Bastien Nocera <[email protected]>
Date: Wed, 15 Oct 2008 15:50:29 +0100
Subject: [PATCH] Remove compilation instructions from sixpair

Not needed anymore

---
 input/sixpair.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)
input/sixpair.c +0 -4
index 5c58b9b..41d7791 100644
@@ -1,7 +1,3 @@
-/* To compile
- * gcc -g -Wall -I../src -I../lib/ -I../include -DSTORAGEDIR=\"/var/lib/bluetooth\" -o sixpair sixpair.c ../src/storage.c ../common/libhelper.a -I../common `pkg-config --libs --cflags glib-2.0 libusb-1.0` -lbluetooth
- */
-
 #include <unistd.h>
 #include <stdio.h>
 #include <inttypes.h>
Signature · 1 line
1.5.5.2
maintainer
#1 lore raw

Hi Bastien,

Quoted 3 lines

Here are the patches to get sixpair support built into BlueZ. It uses libusb-1.0 as well as a yet to be merged libusb-1.0 patch to allow re-attaching a driver to a device.

with the 2.6.28 kernel we should get a better HID driver model (aka HID bus) and then we might not need to libusb stuff anymore. We can go directly to HID and read the descriptors and send vendor HID reports.

Regards

Marcel

maintainer
#2 lore raw
In reply to Bastien Nocera

Hi Bastien,

Quoted 3 lines

Here are the patches to get sixpair support built into BlueZ. It uses libusb-1.0 as well as a yet to be merged libusb-1.0 patch to allow re-attaching a driver to a device.

so I applied all patches except the changes for the build system. I am not sure that this is the right way to go.

If we require libusb-1.0, then we should just change our current code that depends on libusb-0.1 and require libusb-1.0 for all of it.

Quoted 4 lines

Problems left to solve:
- sixaxis enabler code (as seen in enable_sixaxis() in compat/hidd.c) seems to have disappeared from the input plugin. Is that done in the kernel now, or was it just removed?

The kernel is not doing it. Seems to be an oversight.

Quoted 3 lines

- After "cable pairing" the device, I need to unplug/replug the adapter, or restart bluetoothd. Can anyone think of a better way of getting the list of devices updated?

We could use inotify or SIGUSR2 or something to re-read the database.

Quoted 2 lines

- Some minor niggles in the code itself (use D-Bus instead of parsing command-line tools)

Of course.

Quoted 2 lines

- udev rule(s) and parsing only the selected device would be necessary if not required

If we can do this via the HID bus, then we can do it every time and it would not affect the controller itself.

Regards

Marcel

#3 lore raw
Quoted 11 lines · Marcel Holtmann

Hi Bastien,

Quoted 3 lines

Here are the patches to get sixpair support built into BlueZ. It uses libusb-1.0 as well as a yet to be merged libusb-1.0 patch to allow re-attaching a driver to a device.

so I applied all patches except the changes for the build system. I am not sure that this is the right way to go.

If we require libusb-1.0, then we should just change our current code that depends on libusb-0.1 and require libusb-1.0 for all of it.

That'd mean porting:
- dfutool
- avctrl
- bccmd's csr_usb code
- hid2hci

The code isn't too complicated, but I wouldn't be able to test any of the code (apart from maybe hid2hci). Is this something I can promise to do in the future? It's not very complicated, just time consuming.

Quoted 6 lines
Quoted 4 lines

Problems left to solve:
- sixaxis enabler code (as seen in enable_sixaxis() in compat/hidd.c) seems to have disappeared from the input plugin. Is that done in the kernel now, or was it just removed?

The kernel is not doing it. Seems to be an oversight.

OK. I'll re-add the code to the input plugin.

Quoted 5 lines
Quoted 3 lines

- After "cable pairing" the device, I need to unplug/replug the adapter, or restart bluetoothd. Can anyone think of a better way of getting the list of devices updated?

We could use inotify or SIGUSR2 or something to re-read the database.

There's a problem with the current method in that there might be data loss if we're adding data from both bluetoothd, and an external program (both processes writing the same file at the same time).

We could solve the data loss, and update problem by having an internal, root only, dbus method available for cable pairing of that sort. For example, on org.bluez.Adapter:
void AddCablePairedDevice (string name,
string address,
unsigned int vendor_id,
unsigned int product_id,
string pnp_record);

The function would just need to do all the storage work sixpair currently does, and create the device internally similarly to create_stored_device_from_profiles().

It might also be useful to have an internal (non-dbus) API at the manager level for hid proxy dongles (where the adapter wouldn't yet exist when we store the to-be-created devices, not sure how to be certain those devices will be temporary though).

Quoted 10 lines
Quoted 2 lines

- Some minor niggles in the code itself (use D-Bus instead of parsing command-line tools)

Of course.

Quoted 2 lines

- udev rule(s) and parsing only the selected device would be necessary if not required

If we can do this via the HID bus, then we can do it every time and it would not affect the controller itself.

Unless I misunderstood the feature, when claiming the interface, that would actually remove the pad as an input device.

Cheers

maintainer
#4 lore raw

Hi Bastien,

Quoted 16 lines
Quoted 9 lines
Quoted 3 lines

Here are the patches to get sixpair support built into BlueZ. It uses libusb-1.0 as well as a yet to be merged libusb-1.0 patch to allow re-attaching a driver to a device.

so I applied all patches except the changes for the build system. I am not sure that this is the right way to go.

If we require libusb-1.0, then we should just change our current code that depends on libusb-0.1 and require libusb-1.0 for all of it.

That'd mean porting:
- dfutool
- avctrl
- bccmd's csr_usb code
- hid2hci

Quoted 3 lines

The code isn't too complicated, but I wouldn't be able to test any of the code (apart from maybe hid2hci). Is this something I can promise to do in the future? It's not very complicated, just time consuming.

once I upgraded my laptop with the next generation distros, I will start porting dfutool, avctrl and bccmd over. Would be nice if you look at the hid2hci.

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

Problems left to solve:
- sixaxis enabler code (as seen in enable_sixaxis() in compat/hidd.c) seems to have disappeared from the input plugin. Is that done in the kernel now, or was it just removed?

The kernel is not doing it. Seems to be an oversight.

OK. I'll re-add the code to the input plugin.

Any updates here?

Quoted 19 lines
Quoted 5 lines
Quoted 3 lines

- After "cable pairing" the device, I need to unplug/replug the adapter, or restart bluetoothd. Can anyone think of a better way of getting the list of devices updated?

We could use inotify or SIGUSR2 or something to re-read the database.

There's a problem with the current method in that there might be data loss if we're adding data from both bluetoothd, and an external program (both processes writing the same file at the same time).

We could solve the data loss, and update problem by having an internal, root only, dbus method available for cable pairing of that sort. For example, on org.bluez.Adapter:
void AddCablePairedDevice (string name,
string address,
unsigned int vendor_id,
unsigned int product_id,
string pnp_record);

Quoted 8 lines

The function would just need to do all the storage work sixpair currently does, and create the device internally similarly to create_stored_device_from_profiles().

It might also be useful to have an internal (non-dbus) API at the manager level for hid proxy dongles (where the adapter wouldn't yet exist when we store the to-be-created devices, not sure how to be certain those devices will be temporary though).

I think the D-Bus one would be good enough. Check with Claudio and lets come up with a patch proposal.

Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

- Some minor niggles in the code itself (use D-Bus instead of parsing command-line tools)

Of course.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

- udev rule(s) and parsing only the selected device would be necessary if not required

If we can do this via the HID bus, then we can do it every time and it would not affect the controller itself.

Unless I misunderstood the feature, when claiming the interface, that would actually remove the pad as an input device.

Not with the HID bus and the HID raw support. In that case it should be possible.

Regards

Marcel

#5 lore raw

AddCablePairedDevice (was Re: [PATCHes] Add sixpair)

In reply to Bastien Nocera

On Thu, 2008-10-16 at 01:28 +0100, Bastien Nocera wrote:
<snip>

Quoted 9 lines

We could solve the data loss, and update problem by having an internal, root only, dbus method available for cable pairing of that sort. For example, on org.bluez.Adapter:
void AddCablePairedDevice (string name,
string address,
unsigned int vendor_id,
unsigned int product_id,
string pnp_record);

Quoted 3 lines

The function would just need to do all the storage work sixpair currently does, and create the device internally similarly to create_stored_device_from_profiles().

Patch to do that attached.

After setting the master bdaddr on the sixaxis using sixpair, I ran:
dbus-send --system --type=method_call --print-reply --dest="org.bluez" /org/bluez/11043/hci0 org.bluez.Adapter.AddCablePairedDevice string:Foobar string:00:19:C1:61:D6:62 uint32:0x054c uint32:0x0268 string:3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800

Which created the device in bluez. I'd leave it up to sixpair to remove the device from other adapters, and setting the device as trusted (though this didn't seem necessary for the pad to work).

Cheers

src/adapter.c +66 -0
index c1995a3..ba2c5fb 100644
@@ -977,6 +977,36 @@ struct btd_device *adapter_create_device(DBusConnection *conn,
 	return device;
 }
 
+struct btd_device *adapter_add_cable_paired_device(DBusConnection *conn,
+						   struct btd_adapter *adapter,
+						   const char *name,
+						   const char *address,
+						   guint32 vendor_id,
+						   guint32 product_id,
+						   const char *pnp_record)
+{
+	struct btd_device *device;
+	const char *path;
+
+	debug("adapter_add_cable_paired_device(%s)", address);
+
+	device = device_create_cable_paired_device(conn, adapter, name, address, vendor_id, product_id, pnp_record);
+	if (!device)
+		return NULL;
+
+	adapter->devices = g_slist_append(adapter->devices, device);
+
+	path = device_get_path(device);
+	g_dbus_emit_signal(conn, adapter->path,
+			ADAPTER_INTERFACE, "DeviceCreated",
+			DBUS_TYPE_OBJECT_PATH, &path,
+			DBUS_TYPE_INVALID);
+
+	adapter_update_devices(adapter);
+
+	return device;
+}
+
 void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
 				struct btd_device *device)
 {
@@ -1508,6 +1538,41 @@ static DBusMessage *create_device(DBusConnection *conn,
 	return NULL;
 }
 
+static DBusMessage *add_cable_paired_device(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter = data;
+	struct btd_device *device;
+	guint vendor_id, product_id;
+	const gchar *address, *pnp_record, *name;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
+						DBUS_TYPE_STRING, &address,
+						DBUS_TYPE_UINT32, &vendor_id,
+						DBUS_TYPE_UINT32, &product_id,
+						DBUS_TYPE_STRING, &pnp_record,
+						DBUS_TYPE_INVALID) == FALSE)
+		return invalid_args(msg);
+
+	if (check_address(address) < 0)
+		return invalid_args(msg);
+
+	if (adapter_find_device(adapter, address))
+		return g_dbus_create_error(msg,
+				ERROR_INTERFACE ".AlreadyExists",
+				"Device already exists");
+
+	debug("create_device(%s)", address);
+
+	device = adapter_add_cable_paired_device(conn, adapter, name, address, vendor_id, product_id, pnp_record);
+	if (!device)
+		return NULL;
+
+	device_set_temporary(device, FALSE);
+
+	return dbus_message_new_method_return(msg);
+}
+
 static uint8_t parse_io_capability(const char *capability)
 {
 	if (g_str_equal(capability, ""))
@@ -1707,6 +1772,7 @@ static GDBusMethodTable adapter_methods[] = {
 						G_DBUS_METHOD_FLAG_ASYNC},
 	{ "ListDevices",	"",	"ao",	list_devices,
 						G_DBUS_METHOD_FLAG_DEPRECATED},
+	{ "AddCablePairedDevice", "ssuus", "o",	add_cable_paired_device	},
 	{ "CreateDevice",	"s",	"o",	create_device,
 						G_DBUS_METHOD_FLAG_ASYNC},
 	{ "CreatePairedDevice",	"sos",	"o",	create_paired_device,
src/adapter.h +8 -0
index 06f558a..1a24a1a 100644
@@ -91,6 +91,14 @@ void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
 struct btd_device *adapter_create_device(DBusConnection *conn,
 				struct btd_adapter *adapter, const char *address);
 
+struct btd_device *adapter_add_cable_paired_device(DBusConnection *conn,
+				struct btd_adapter *adapter,
+				const char *name,
+				const char *address,
+				guint vendor_id,
+				guint product_id,
+				const char *pnp_record);
+
 int pending_remote_name_cancel(struct btd_adapter *adapter);
 
 void remove_pending_device(struct btd_adapter *adapter);
src/device.c +51 -0

57 lines not on this page · raw message

src/device.h +7 -0
index 5c230b8..a3e5447 100644
@@ -36,6 +36,13 @@ typedef enum {
 
 struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter,
 				const gchar *address);
+struct btd_device *device_create_cable_paired_device(DBusConnection *conn,
+						     struct btd_adapter *adapter,
+						     const char *name,
+						     const char *address,
+						     guint32 vendor_id,
+						     guint32 product_id,
+						     const char *pnp_record);
 void device_set_name(struct btd_device *device, const char *name);
 void device_remove(struct btd_device *device, DBusConnection *conn,
 						gboolean remove_stored);
maintainer
#6 lore raw

Re: AddCablePairedDevice (was Re: [PATCHes] Add sixpair)

Hi Bastien,

Quoted 13 lines
Quoted 9 lines

We could solve the data loss, and update problem by having an internal, root only, dbus method available for cable pairing of that sort. For example, on org.bluez.Adapter:
void AddCablePairedDevice (string name,
string address,
unsigned int vendor_id,
unsigned int product_id,
string pnp_record);

Quoted 3 lines

The function would just need to do all the storage work sixpair currently does, and create the device internally similarly to create_stored_device_from_profiles().

Quoted 8 lines

Patch to do that attached.

After setting the master bdaddr on the sixaxis using sixpair, I ran:
dbus-send --system --type=method_call --print-reply --dest="org.bluez" /org/bluez/11043/hci0 org.bluez.Adapter.AddCablePairedDevice string:Foobar string:00:19:C1:61:D6:62 uint32:0x054c uint32:0x0268 string:3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800

Which created the device in bluez. I'd leave it up to sixpair to remove the device from other adapters, and setting the device as trusted (though this didn't seem necessary for the pad to work).

can this be made a little bit more generic. For example Bluetooth 2.1 has the out-of-band (OOB) ways for Simple Pairing and if we can design something generic here that would help a lot.

Regards

Marcel

#7 lore raw

Re: AddCablePairedDevice (was Re: [PATCHes] Add sixpair)

Quoted 3 lines · Marcel Holtmann

Hi Bastien,
=20

Quoted 1 line
Quoted 1 line

We could solve the data loss, and update problem by having an interna=

l,

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

root only, dbus method available for cable pairing of that sort. For example, on org.bluez.Adapter:
void AddCablePairedDevice (string name,
string address,
unsigned int vendor_id, unsigned int product_id, string pnp_record);
=20
The function would just need to do all the storage work sixpair currently does, and create the device internally similarly to create_stored_device_from_profiles().

Quoted 5 lines
Quoted 5 lines

=20
Patch to do that attached.
=20
After setting the master bdaddr on the sixaxis using sixpair, I ran:
dbus-send --system --type=3Dmethod_call --print-reply --dest=3D"org.blu=

ez" /org/bluez/11043/hci0 org.bluez.Adapter.AddCablePairedDevice string:Foo= bar string:00:19:C1:61:D6:62 uint32:0x054c uint32:0x0268 string:36019209000= 00A000100000900013503191124090004350D35061901000900113503190011090006350909= 656E09006A0901000900093508350619112409010009000D350F350D3506190100090013350= 31900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C= 65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E74657= 27461696E6D656E740902000901000902010901000902020800090203082109020428010902= 052801090206359A35980822259405010904A101A102850175089501150026FF00810375019= 513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A100= 75089504350046FF0009300931093209358102C005017508952709018102750895300901910= 2750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A102= 85EF750895300901B102C0C0090207350835060904090901000902082800090209280109020= A280109020B09010009020C093E8009020D280009020E2800

Quoted 8 lines
Quoted 4 lines

=20
Which created the device in bluez. I'd leave it up to sixpair to remove the device from other adapters, and setting the device as trusted (though this didn't seem necessary for the pad to work).

=20
can this be made a little bit more generic. For example Bluetooth 2.1 has the out-of-band (OOB) ways for Simple Pairing and if we can design something generic here that would help a lot.

What does it need for SP to work?