From 22e68ea53c5b9faab415bfc46db42e1e9b34a745 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 5 Jun 2009 13:14:16 +0000 Subject: [PATCH] - Add patch to allow Sixaxis pairing --- 0001-Add-sixaxis-cable-pairing-plugin.patch | 504 ++++++++++++++++++++ bluez.spec | 14 +- 2 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 0001-Add-sixaxis-cable-pairing-plugin.patch diff --git a/0001-Add-sixaxis-cable-pairing-plugin.patch b/0001-Add-sixaxis-cable-pairing-plugin.patch new file mode 100644 index 0000000..72cbc75 --- /dev/null +++ b/0001-Add-sixaxis-cable-pairing-plugin.patch @@ -0,0 +1,504 @@ +From f23a9556acf6308e217b11e0a882e89d799f2517 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +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 ++ * ++ * ++ * 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 ++#endif ++ ++#define G_UDEV_API_IS_SUBJECT_TO_CHANGE ++#include ++#include ++#include ++#include ++#include ++ ++#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 + diff --git a/bluez.spec b/bluez.spec index 8016a81..2bed1d8 100644 --- a/bluez.spec +++ b/bluez.spec @@ -1,7 +1,7 @@ Summary: Bluetooth utilities Name: bluez Version: 4.40 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ Group: Applications/System Source: http://www.kernel.org/pub/linux/bluetooth/%{name}-%{version}.tar.gz @@ -22,6 +22,8 @@ Patch2: bluez-try-utf8-harder.patch Patch3: bluez-activate-wacom-mode2.patch # https://bugzilla.redhat.com/show_bug.cgi?id=498756 Patch4: bluez-socket-mobile-cf-connection-kit.patch +# http://thread.gmane.org/gmane.linux.bluez.kernel/2396 +Patch5: 0001-Add-sixaxis-cable-pairing-plugin.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root URL: http://www.bluez.org/ @@ -31,6 +33,11 @@ BuildRequires: dbus-devel >= 0.90 BuildRequires: libusb-devel, glib2-devel, alsa-lib-devel BuildRequires: gstreamer-plugins-base-devel, gstreamer-devel BuildRequires: libsndfile-devel +# For cable pairing +BuildRequires: libgudev-devel, libusb1-devel + +# For rebuild +BuildRequires: libtool autoconf automake Obsoletes: bluez-pan < 4.0, bluez-sdp < 4.0 Requires: initscripts, bluez-libs = %{version} @@ -121,8 +128,10 @@ This includes hidd, dund and pand. %patch2 -p1 -b .non-utf8-name %patch3 -p1 -b .wacom %patch4 -p1 -b .socket-mobile +%patch5 -p1 -b .cable-pairing %build +autoreconf %configure --enable-cups --enable-hid2hci --enable-dfutool --enable-tools --enable-bccmd --enable-gstreamer --enable-hidd --enable-pand --enable-dund make @@ -259,6 +268,9 @@ fi %config(noreplace) %{_sysconfdir}/sysconfig/pand %changelog +* Fri Jun 05 2009 Bastien Nocera 4.40-2 +- Add patch to allow Sixaxis pairing + * Tue May 19 2009 Bastien Nocera 4.40-1 - Update to 4.40