diff --git a/0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch b/0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch index 447e951..e583320 100644 --- a/0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch +++ b/0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch @@ -1,17 +1,17 @@ -From 3aca31788655582f3029b3c88ad6f468c4de07a2 Mon Sep 17 00:00:00 2001 +From aa73bf5039dfd2cf0a52dd6fd22501d955cc1a00 Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 10 Jan 2013 09:18:43 +0100 Subject: [PATCH] work around Logitech diNovo Edge keyboard firmware issue https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/269851 --- - scripts/bluetooth-hid2hci.rules | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) + tools/hid2hci.rules | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) -diff --git a/scripts/bluetooth-hid2hci.rules b/scripts/bluetooth-hid2hci.rules -index 0687c8a..2a571e5 100644 ---- a/scripts/bluetooth-hid2hci.rules -+++ b/scripts/bluetooth-hid2hci.rules +diff --git a/tools/hid2hci.rules b/tools/hid2hci.rules +index db6bb03..7db4572 100644 +--- a/tools/hid2hci.rules ++++ b/tools/hid2hci.rules @@ -11,7 +11,10 @@ ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProt RUN+="hid2hci --method=dell --devpath=%p", ENV{HID2HCI_SWITCH}="1" diff --git a/bluez-uinput.modules b/bluez-uinput.modules deleted file mode 100644 index 9f721d9..0000000 --- a/bluez-uinput.modules +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -if [ ! -c /dev/input/uinput ] ; then - exec /sbin/modprobe uinput >/dev/null 2>&1 -fi - diff --git a/bluez.spec b/bluez.spec index fc72d70..10a090d 100644 --- a/bluez.spec +++ b/bluez.spec @@ -1,24 +1,25 @@ Summary: Bluetooth utilities Name: bluez -Version: 4.101 -Release: 10%{?dist} +Version: 5.5 +Release: 1%{?dist} License: GPLv2+ Group: Applications/System URL: http://www.bluez.org/ -Source: http://www.kernel.org/pub/linux/bluetooth/%{name}-%{version}.tar.gz +Source0: http://www.kernel.org/pub/linux/bluetooth/bluez-%{version}.tar.xz Source1: bluez.gitignore -Source8: bluez-uinput.modules -# Ubuntu patches -Patch14: 0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch +## https://bugzilla.redhat.com/show_bug.cgi?id=874015#c0 +Patch1: playstation-peripheral-pugin-v5.x.patch +## Ubuntu patches +Patch2: 0001-work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch BuildRequires: git BuildRequires: flex BuildRequires: dbus-devel >= 0.90 BuildRequires: libusb-devel, glib2-devel -BuildRequires: libsndfile-devel BuildRequires: libcap-ng-devel +BuildRequires: libical-devel BuildRequires: readline-devel # For cable pairing BuildRequires: systemd-devel @@ -35,9 +36,6 @@ Requires: bluez-libs = %{version}-%{release} Requires: systemd Requires: dbus >= 0.60 Requires: hwdata >= 0.215 -%ifnarch s390 s390x -Requires: dbus-bluez-pin-helper -%endif Requires(preun): /bin/systemctl Requires(post): /bin/systemctl @@ -53,6 +51,14 @@ Utilities for use in Bluetooth applications: - hciconfig - bluetoothd - l2ping + - rfcomm + - sdptool + - bccmd + - bluetoothctl + - btmon + - hcidump + - l2test + - rctest - start scripts (Red Hat) - pcmcia configuration files @@ -125,16 +131,17 @@ git am -p1 %{patches} < /dev/null %build libtoolize -f -c -autoreconf -vif -%configure --enable-cups --enable-dfutool --enable-tools --enable-bccmd --enable-hid2hci --with-ouifile=/usr/share/hwdata/oui.txt --with-systemdsystemunitdir=/lib/systemd/system --enable-wiimote +autoreconf -f -i +%configure --enable-cups --enable-tools --enable-library \ + --with-systemdsystemunitdir=/lib/systemd/system \ + --with-systemduserunitdir=/lib/systemd/user make V=1 %install make install DESTDIR=$RPM_BUILD_ROOT /sbin/ldconfig -n $RPM_BUILD_ROOT/%{_libdir} # Remove autocrap and libtool droppings -rm -f $RPM_BUILD_ROOT/%{_libdir}/*.la \ - $RPM_BUILD_ROOT/%{_libdir}/bluetooth/plugins/*.la \ +rm $RPM_BUILD_ROOT/%{_libdir}/*.la # Remove the cups backend from libdir, and install it in /usr/lib whatever the install if test -d ${RPM_BUILD_ROOT}/usr/lib64/cups ; then @@ -142,20 +149,15 @@ if test -d ${RPM_BUILD_ROOT}/usr/lib64/cups ; then rm -rf ${RPM_BUILD_ROOT}%{_libdir}/cups fi -rm -f ${RPM_BUILD_ROOT}/%{_sysconfdir}/bluetooth/rfcomm.conf - -rm -f ${RPM_BUILD_ROOT}/%{_sysconfdir}/udev/*.rules ${RPM_BUILD_ROOT}/lib/udev/rules.d/*.rules -install -D -p -m0644 scripts/bluetooth-serial.rules ${RPM_BUILD_ROOT}/lib/udev/rules.d/97-bluetooth-serial.rules -install -D -p -m0644 scripts/bluetooth-hid2hci.rules ${RPM_BUILD_ROOT}/lib/udev/rules.d/97-bluetooth-hid2hci.rules -install -D -m0755 scripts/bluetooth_serial ${RPM_BUILD_ROOT}/lib/udev/bluetooth_serial - -install -D -m0755 %{SOURCE8} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/modules/bluez-uinput.modules +rm -f ${RPM_BUILD_ROOT}/%{_sysconfdir}/udev/*.rules ${RPM_BUILD_ROOT}/usr/lib/udev/rules.d/*.rules +install -D -p -m0644 tools/hid2hci.rules ${RPM_BUILD_ROOT}/lib/udev/rules.d/97-hid2hci.rules install -d -m0755 $RPM_BUILD_ROOT/%{_localstatedir}/lib/bluetooth mkdir -p $RPM_BUILD_ROOT/%{_libdir}/bluetooth/ -install -D -p -m0644 audio/audio.conf ${RPM_BUILD_ROOT}/etc/bluetooth/ +install -d -m0755 ${RPM_BUILD_ROOT}/etc/bluetooth/ +install -D -p -m0644 profiles/audio/audio.conf ${RPM_BUILD_ROOT}/etc/bluetooth/ %post libs -p /sbin/ldconfig @@ -187,31 +189,41 @@ fi %files %defattr(-,root,root,-) %{_bindir}/ciptool -%{_bindir}/dfutool %{_bindir}/hcitool %{_bindir}/l2ping %{_bindir}/rfcomm %{_bindir}/sdptool -%{_bindir}/gatttool -%{_sbindir}/* +%{_bindir}/bccmd +%{_bindir}/bluetoothctl +%{_bindir}/btmon +%{_bindir}/hciattach +%{_bindir}/hciconfig +%{_bindir}/hcidump +%{_bindir}/l2test +%{_bindir}/rctest %{_mandir}/man1/ciptool.1.gz -%{_mandir}/man1/dfutool.1.gz %{_mandir}/man1/hcitool.1.gz %{_mandir}/man1/rfcomm.1.gz %{_mandir}/man1/sdptool.1.gz +%{_mandir}/man1/bccmd.1.* +%{_mandir}/man1/hciattach.1.* +%{_mandir}/man1/hciconfig.1.* +%{_mandir}/man1/hcidump.1.* +%{_mandir}/man1/l2ping.1.* +%{_mandir}/man1/rctest.1.* %{_mandir}/man8/* -%exclude %{_mandir}/man8/hid2hci.8* %dir %{_sysconfdir}/bluetooth/ -%config(noreplace) %{_sysconfdir}/bluetooth/main.conf %config(noreplace) %{_sysconfdir}/bluetooth/audio.conf -%config(noreplace) %{_sysconfdir}/sysconfig/modules/bluez-uinput.modules +%{_libexecdir}/bluetooth/bluetoothd +%{_libexecdir}/bluetooth/obexd +%exclude %{_mandir}/man1/hid2hci.1* %config %{_sysconfdir}/dbus-1/system.d/bluetooth.conf %{_libdir}/bluetooth/ -/lib/udev/bluetooth_serial -/lib/udev/rules.d/97-bluetooth-serial.rules %{_localstatedir}/lib/bluetooth %{_datadir}/dbus-1/system-services/org.bluez.service -/usr/lib/systemd/system/bluetooth.service +%{_datadir}/dbus-1/services/org.bluez.obex.service +/lib/systemd/system/bluetooth.service +/lib/systemd/user/obex.service %files libs %defattr(-,root,root,-) @@ -232,11 +244,14 @@ fi %files hid2hci %defattr(-,root,root,-) /usr/lib/udev/hid2hci -%{_mandir}/man8/hid2hci.8* -/lib/udev/rules.d/97-bluetooth-hid2hci.rules -%exclude /usr/lib/udev/rules.d/97-bluetooth-hid2hci.rules +%{_mandir}/man1/hid2hci.1* +/lib/udev/rules.d/97-hid2hci.rules %changelog +* Sat Aug 10 2013 Kalev Lember - 5.5-1 +- Update to 5.5, based on earlier work from + https://bugzilla.redhat.com/show_bug.cgi?id=974145 + * Sat Aug 03 2013 Fedora Release Engineering - 4.101-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild diff --git a/playstation-peripheral-pugin-v5.x.patch b/playstation-peripheral-pugin-v5.x.patch new file mode 100644 index 0000000..222f023 --- /dev/null +++ b/playstation-peripheral-pugin-v5.x.patch @@ -0,0 +1,1028 @@ +From 76986f1d8d356ddd6a1c31190627ecbe8ab1d773 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Mon, 19 Sep 2011 18:15:40 +0200 +Subject: [PATCH 1/5] adapter: add a btd_adapter_get_default_address() call +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +Add a new btd_* call to get the default adapter address as a string. + +This is meant to be used, for instance, by _external_ plugins which want +to know the default adapter address for some reason (e.g. to send it to +a device for some custom pairing scheme like in the case of Playstation +peripherals). + +External plugins can only use symbols marked as "global" in +src/bluetooth.ver, this patch avoids making global these symbols: + + adapter_get_address + bt_malloc + ba2str +--- + src/adapter.c | 17 +++++++++++++++++ + src/adapter.h | 1 + + 2 files changed, 18 insertions(+) + +diff --git a/src/adapter.c b/src/adapter.c +index 1250966..a7a2530 100644 +--- a/src/adapter.c ++++ b/src/adapter.c +@@ -224,6 +224,23 @@ struct btd_adapter *btd_adapter_get_default(void) + return NULL; + } + ++char *btd_adapter_get_default_address(void) ++{ ++ struct btd_adapter *adapter; ++ char *str; ++ ++ adapter = btd_adapter_get_default(); ++ if (adapter == NULL) ++ return NULL; ++ ++ str = bt_malloc(18); ++ if (str == NULL) ++ return NULL; ++ ++ ba2str(adapter_get_address(adapter), str); ++ return str; ++} ++ + bool btd_adapter_is_default(struct btd_adapter *adapter) + { + if (!adapter) +diff --git a/src/adapter.h b/src/adapter.h +index 2de8730..ed99b55 100644 +--- a/src/adapter.h ++++ b/src/adapter.h +@@ -38,6 +38,7 @@ + struct btd_adapter; + + struct btd_adapter *btd_adapter_get_default(void); ++char *btd_adapter_get_default_address(void); + bool btd_adapter_is_default(struct btd_adapter *adapter); + uint16_t btd_adapter_get_index(struct btd_adapter *adapter); + +-- +1.7.10.4 + + +From 2321b3b669de2edc3a9be2e1980c4b1f5312e176 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Mon, 19 Sep 2011 18:13:57 +0200 +Subject: [PATCH 2/5] adapter: add a btd_create_stored_device() call +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +Add a new btd_* call to add a new device to the database of known +devices. + +This is particularly useful to register Bluetooth devices using +a non-Bluetooth mechanism (e.g. USB-pairing in the case of Playstation +peripherals). + +The interface uses a btd_ prefix and relies only on native C types in +order to be more easily used by _external_ plugins. + +External plugins can only use symbols marked as "global" in +src/bluetooth.ver, this patch avoids making global these symbols: + + store_sdp_record + str2ba + adapter_get_device + device_set_name + device_set_temporary + device_set_trusted +--- + src/adapter.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/adapter.h | 11 +++++++++++ + 2 files changed, 63 insertions(+) + +diff --git a/src/adapter.c b/src/adapter.c +index a7a2530..ea3a739 100644 +--- a/src/adapter.c ++++ b/src/adapter.c +@@ -6318,3 +6318,55 @@ void adapter_shutdown(void) + if (!adapter_remaining) + btd_exit(); + } ++ ++int btd_create_stored_device(char *adapter_address, ++ char *device_address, ++ char *name, ++ uint16_t vendor_id_source, ++ uint16_t vendor_id, ++ uint16_t product_id, ++ uint16_t version_id, ++ const char *uuid, ++ char *sdp_record, ++ bool trusted) ++{ ++ struct btd_adapter *adapter; ++ struct btd_device *device; ++ bdaddr_t dst; ++ int ret = 0; ++ ++ store_sdp_record(adapter_address, device_address, 0x10000, sdp_record); ++ ++ str2ba(device_address, &dst); ++ ++ adapter = btd_adapter_get_default(); ++ if (adapter == NULL) { ++ DBG("Failed to get the adapter"); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ /* This will create the device if necessary */ ++ device = adapter_get_device(adapter, &dst, BDADDR_BREDR); ++ if (device == NULL) { ++ DBG("Failed to get the device"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ if (name) ++ device_set_name(device, name); ++ ++ btd_device_set_pnpid(device, vendor_id_source, ++ vendor_id, product_id, version_id); ++ ++ if (uuid) ++ btd_device_add_uuid(device, uuid); ++ ++ device_set_temporary(device, FALSE); ++ ++ if (trusted) ++ device_set_trusted(device, TRUE); ++out: ++ return ret; ++} +diff --git a/src/adapter.h b/src/adapter.h +index ed99b55..2abc9ce 100644 +--- a/src/adapter.h ++++ b/src/adapter.h +@@ -214,3 +214,14 @@ gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter); + void btd_adapter_for_each_device(struct btd_adapter *adapter, + void (*cb)(struct btd_device *device, void *data), + void *data); ++ ++int btd_create_stored_device(char *adapter_address, ++ char *device_address, ++ char *name, ++ uint16_t vendor_id_source, ++ uint16_t vendor_id, ++ uint16_t product_id, ++ uint16_t version_id, ++ const char *uuid, ++ char *sdp_record, ++ bool trusted); +-- +1.7.10.4 + + +From bbdb42cb551fc8600025e2832cf6bf08fc51337e Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Wed, 5 May 2010 13:43:09 +0200 +Subject: [PATCH 3/5] Add playstation-peripheral plugin: USB pairing and LEDs + settings +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +Add a plugin which handles the connection of a Playstation peripheral, +when a new hidraw device is connected the plugin: + + - Filters udev events, and select the Playstation peripheral + - Sets the Master bluetooth address in the peripheral (USB pairing) + - Sets LEDs to match the joystick system number if needed + (for USB and BT) + - Adds the device to the database of the current default + adapter (BT association) + +Signed-off-by: Bastien Nocera +Signed-off-by: Antonio Ospite +--- + Makefile.am | 7 + + configure.ac | 10 + + plugins/playstation-peripheral-hid.c | 263 ++++++++++++++++++++++ + plugins/playstation-peripheral-hid.h | 10 + + plugins/playstation-peripheral.c | 401 ++++++++++++++++++++++++++++++++++ + 5 files changed, 691 insertions(+) + create mode 100644 plugins/playstation-peripheral-hid.c + create mode 100644 plugins/playstation-peripheral-hid.h + create mode 100644 plugins/playstation-peripheral.c + +diff --git a/Makefile.am b/Makefile.am +index 9d570fb..a78a8ba 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -112,6 +112,13 @@ builtin_nodist = + + include Makefile.plugins + ++if PLAYSTATION_PERIPHERAL_PLUGIN ++plugin_LTLIBRARIES += plugins/playstation-peripheral.la ++plugins_playstation_peripheral_la_SOURCES = plugins/playstation-peripheral.c plugins/playstation-peripheral-hid.c ++plugins_playstation_peripheral_la_LDFLAGS = -module -avoid-version -no-undefined @UDEV_LIBS@ ++plugins_playstation_peripheral_la_CFLAGS = -fvisibility=hidden @DBUS_CFLAGS@ @GLIB_CFLAGS@ @UDEV_CFLAGS@ ++endif ++ + if MAINTAINER_MODE + plugin_LTLIBRARIES += plugins/external-dummy.la + plugins_external_dummy_la_SOURCES = plugins/external-dummy.c +diff --git a/configure.ac b/configure.ac +index f3c58be..7e0cc0c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -229,6 +229,16 @@ AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental], + [enable_experimental=${enableval}]) + AM_CONDITIONAL(EXPERIMENTAL, test "${enable_experimental}" = "yes") + ++AC_ARG_ENABLE(playstation_peripheral, AC_HELP_STRING([--enable-playstation-peripheral], ++ [enable playstation-peripheral plugin]), ++ [enable_playstation_peripheral=${enableval}]) ++ ++if (test "${enble_playstation_peripheral}" != "no" && test "${enable_udev}" != "no"); then ++ AC_DEFINE(HAVE_PLAYSTATION_PERIPHERAL_PLUGIN, 1, [Define to 1 if you have playstation-peripheral plugin.]) ++fi ++ ++AM_CONDITIONAL(PLAYSTATION_PERIPHERAL_PLUGIN, test "${enable_playstation_peripheral}" != "no" && test "${enable_udev}" != "no") ++ + if (test "${prefix}" = "NONE"); then + dnl no prefix and no localstatedir, so default to /var + if (test "$localstatedir" = '${prefix}/var'); then +diff --git a/plugins/playstation-peripheral-hid.c b/plugins/playstation-peripheral-hid.c +new file mode 100644 +index 0000000..9c5e530 +--- /dev/null ++++ b/plugins/playstation-peripheral-hid.c +@@ -0,0 +1,263 @@ ++/* ++ * playstation peripheral plugin: lowlevel hid functions ++ * ++ * Copyright (C) 2011 Antonio Ospite ++ * ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "log.h" ++#include "playstation-peripheral-hid.h" ++ ++/* Fallback definitions to compile with older headers */ ++#ifndef HIDIOCGFEATURE ++#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) ++#endif ++ ++#ifndef HIDIOCSFEATURE ++#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) ++#endif ++ ++#define BDADDR_STR_SIZE 18 /* strlen("00:00:00:00:00:00") + 1 */ ++ ++#define LED_1 (0x01 << 1) ++#define LED_2 (0x01 << 2) ++#define LED_3 (0x01 << 3) ++#define LED_4 (0x01 << 4) ++ ++#define LED_STATUS_OFF 0 ++#define LED_STATUS_ON 1 ++ ++/* Usb cable pairing section */ ++static unsigned char *get_feature_report(int fd, uint8_t report_number, ++ unsigned int len) ++{ ++ unsigned char *buf; ++ int ret; ++ ++ buf = calloc(len, sizeof(*buf)); ++ if (buf == NULL) { ++ error("%s:%s() calloc failed", __FILE__, __func__); ++ return NULL; ++ } ++ ++ buf[0] = report_number; ++ ++ ret = ioctl(fd, HIDIOCGFEATURE(len), buf); ++ if (ret < 0) { ++ error("%s:%s() HIDIOCGFEATURE ret = %d", ++ __FILE__, __func__, ret); ++ free(buf); ++ return NULL; ++ } ++ ++ return buf; ++} ++ ++static int set_feature_report(int fd, uint8_t *report, int len) ++{ ++ int ret; ++ ++ ret = ioctl(fd, HIDIOCSFEATURE(len), report); ++ if (ret < 0) ++ error("%s:%s() HIDIOCSFEATURE failed, ret = %d", ++ __FILE__, __func__, ret); ++ ++ return ret; ++} ++ ++char *sixaxis_get_device_bdaddr(int fd) ++{ ++ unsigned char *buf; ++ char *address; ++ ++ buf = get_feature_report(fd, 0xf2, 18); ++ if (buf == NULL) { ++ error("%s:%s() cannot get feature report", __FILE__, __func__); ++ return NULL; ++ } ++ ++ address = calloc(BDADDR_STR_SIZE, sizeof(*address)); ++ if (address == NULL) { ++ error("%s:%s() calloc failed", __FILE__, __func__); ++ free(buf); ++ return NULL; ++ } ++ ++ snprintf(address, BDADDR_STR_SIZE, ++ "%02X:%02X:%02X:%02X:%02X:%02X", ++ buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]); ++ ++ free(buf); ++ return address; ++} ++ ++char *sixaxis_get_master_bdaddr(int fd) ++{ ++ unsigned char *buf; ++ char *address; ++ ++ buf = get_feature_report(fd, 0xf5, 8); ++ if (buf == NULL) { ++ error("%s:%s() cannot get feature report", __FILE__, __func__); ++ return NULL; ++ } ++ ++ address = calloc(BDADDR_STR_SIZE, sizeof(*address)); ++ if (address == NULL) { ++ error("%s:%s() calloc failed", __FILE__, __func__); ++ free(buf); ++ return NULL; ++ } ++ ++ snprintf(address, BDADDR_STR_SIZE, ++ "%02X:%02X:%02X:%02X:%02X:%02X", ++ buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); ++ ++ free(buf); ++ return address; ++} ++ ++int sixaxis_set_master_bdaddr(int fd, char *adapter_bdaddr) ++{ ++ uint8_t *report; ++ uint8_t addr[6]; ++ int ret; ++ ++ ret = sscanf(adapter_bdaddr, ++ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ &addr[0], &addr[1], &addr[2], ++ &addr[3], &addr[4], &addr[5]); ++ if (ret != 6) { ++ error("%s:%s() Parsing the bt address failed", ++ __FILE__, __func__); ++ return -EINVAL; ++ } ++ ++ report = malloc(8); ++ if (report == NULL) { ++ error("%s:%s() malloc failed", __FILE__, __func__); ++ return -ENOMEM; ++ } ++ ++ report[0] = 0xf5; ++ report[1] = 0x01; ++ ++ report[2] = addr[0]; ++ report[3] = addr[1]; ++ report[4] = addr[2]; ++ report[5] = addr[3]; ++ report[6] = addr[4]; ++ report[7] = addr[5]; ++ ++ ret = set_feature_report(fd, report, 8); ++ if (ret < 0) { ++ error("%s:%s() cannot set feature report", ++ __FILE__, __func__); ++ goto out; ++ } ++ ++ DBG("New Master Bluetooth address: %s", adapter_bdaddr); ++ ++out: ++ free(report); ++ return ret; ++} ++ ++ ++/* Led setting section */ ++static int set_leds(int fd, unsigned char leds_status[4]) ++{ ++ int ret; ++ ++ /* ++ * the total time the led is active (0xff means forever) ++ * | duty_length: how long a cycle is in deciseconds: ++ * | | (0 means "blink very fast") ++ * | | ??? (Maybe a phase shift or duty_length multiplier?) ++ * | | | % of duty_length led is off (0xff means 100%) ++ * | | | | % of duty_length led is on (0xff is 100%) ++ * | | | | | ++ * 0xff, 0x27, 0x10, 0x00, 0x32, ++ */ ++ unsigned char leds_report[] = { ++ 0x01, ++ 0x00, 0x00, 0x00, 0x00, 0x00, /* rumble values TBD */ ++ 0x00, 0x00, 0x00, 0x00, 0x1e, /* LED_1=0x02, LED_2=0x04 ... */ ++ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_4 */ ++ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_3 */ ++ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_2 */ ++ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_1 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, ++ }; ++ ++ int leds = 0; ++ if (leds_status[0]) ++ leds |= LED_1; ++ if (leds_status[1]) ++ leds |= LED_2; ++ if (leds_status[2]) ++ leds |= LED_3; ++ if (leds_status[3]) ++ leds |= LED_4; ++ ++ leds_report[10] = leds; ++ ++ ret = write(fd, leds_report, sizeof(leds_report)); ++ if (ret < (ssize_t) sizeof(leds_report)) ++ error("%s:%s() Unable to write to hidraw device", ++ __FILE__, __func__); ++ ++ return ret; ++} ++ ++int set_controller_number(int fd, unsigned int n) ++{ ++ unsigned char leds_status[4] = {0, 0, 0, 0}; ++ ++ switch (n) { ++ case 0: ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ leds_status[n - 1] = LED_STATUS_ON; ++ break; ++ case 5: ++ case 6: ++ case 7: ++ leds_status[4 - 1] = LED_STATUS_ON; ++ leds_status[n - 4 - 1] = LED_STATUS_ON; ++ break; ++ default: ++ error("%s:%s() Only 7 controllers supported for now", ++ __FILE__, __func__); ++ return -1; ++ } ++ ++ return set_leds(fd, leds_status); ++} +diff --git a/plugins/playstation-peripheral-hid.h b/plugins/playstation-peripheral-hid.h +new file mode 100644 +index 0000000..ade8fa0 +--- /dev/null ++++ b/plugins/playstation-peripheral-hid.h +@@ -0,0 +1,10 @@ ++#ifndef __PLAYSTATION_PERIPHERAL_HID_H ++#define __PLAYSTATION_PERIPHERAL_HID_H ++ ++char *sixaxis_get_device_bdaddr(int fd); ++char *sixaxis_get_master_bdaddr(int fd); ++int sixaxis_set_master_bdaddr(int fd, char *adapter_bdaddr); ++ ++int set_controller_number(int fd, unsigned int n); ++ ++#endif /* __PLAYSTATION_PERIPHERAL_HID_H */ +diff --git a/plugins/playstation-peripheral.c b/plugins/playstation-peripheral.c +new file mode 100644 +index 0000000..9238e92 +--- /dev/null ++++ b/plugins/playstation-peripheral.c +@@ -0,0 +1,401 @@ ++/* ++ * playstation peripheral plugin: support for Playstation peripherals ++ * ++ * Copyright (C) 2009 Bastien Nocera ++ * Copyright (C) 2011 Antonio Ospite ++ * ++ * ++ * 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 ++ * ++ */ ++ ++/* ++ * In the following this terminology is used: ++ * ++ * - peripheral: a Playstation peripheral (Sixaxis, DS3, headset, etc.) ++ * - controller: an input peripheral ++ * - adapter: the bluetooth dongle on the host system. ++ * - adapter_bdaddr: the bdaddr of the bluetooth adapter. ++ * - device_bdaddr: the bdaddr of the Playstation peripheral. ++ * - master_bdaddr: the bdaddr of the adapter to be configured into the ++ * Playstation peripheral ++ * ++ * WHAT we need the plugin to do: ++ * ++ * - When a device is connected via USB: ++ * + Fetch the (default) adapter bdaddr (from BlueZ) and store it into ++ * the device ++ * + Fetch the device bdaddr (from the device via USB/HID) and make the ++ * device _trusted_ by the adapter (is "trusted" the correct term ++ * here? Or maybe this is more like a "static association"? Are the ++ * term "trusted" and "associated" in bluetooth context defined ++ * anywhere?) ++ * ++ * - When the device is connected via BT: ++ * + Nothing! It should work automatically. ++ * ++ * - Set LEDs when possible. ++ * ++ * WHY we need that: ++ * ++ * Playstation peripherals require/support USB cable pairing. ++ * ++ * It is required in the sense that devices will talk only to adapters ++ * they know. ++ * ++ * It is supported in the sense that this mechanism is optional on _some_ ++ * devices like the PS3 Keypad. ++ * ++ * On the PS3 these cable paired devices can be used via BT without ++ * further association steps once they have been connected ++ * _at_least_once_ via USB to a certain host (with a certain BT adapter ++ * that is), we would like to have the same behavior with BlueZ. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1 ++#include ++ ++#include "plugin.h" ++#include "log.h" ++#include "adapter.h" ++#include "device.h" ++#include "storage.h" ++#include "sdp_lib.h" ++ ++#include "playstation-peripheral-hid.h" ++ ++struct playstation_peripheral { ++ uint16_t vendor_id; ++ uint16_t product_id; ++ char *name; ++ char *sdp_record; ++ char *uuid; ++ ++ /* device specific callbacks to get master/device bdaddr and set ++ * master bdaddr ++ */ ++ char * (*get_device_bdaddr)(int); ++ char * (*get_master_bdaddr)(int); ++ int (*set_master_bdaddr) (int, char *); ++}; ++ ++static struct playstation_peripheral peripherals[] = { ++ { ++ .vendor_id = 0x054c, ++ .product_id = 0x0268, ++ .name = "PLAYSTATION(R)3 Controller", ++ .sdp_record = "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800", ++ .uuid = "00001124-0000-1000-8000-00805f9b34fb", ++ .get_device_bdaddr = sixaxis_get_device_bdaddr, ++ .get_master_bdaddr = sixaxis_get_master_bdaddr, ++ .set_master_bdaddr = sixaxis_set_master_bdaddr, ++ }, ++}; ++ ++static struct udev *ctx; ++static struct udev_monitor *monitor; ++static guint watch_id; ++ ++static int create_peripheral_association(char *adapter_address, ++ char *device_address, ++ struct playstation_peripheral *peripheral) ++{ ++ return btd_create_stored_device(adapter_address, device_address, ++ peripheral->name, ++ 0x0002, /* VersionIDSource = USB Implementer's Forum */ ++ peripheral->vendor_id, ++ peripheral->product_id, ++ 0, /* version is hardcoded to 0 for now */ ++ peripheral->uuid, ++ peripheral->sdp_record, ++ 1); ++} ++ ++static int peripheral_pair(int fd, char *adapter_bdaddr, ++ struct playstation_peripheral *peripheral) ++{ ++ char *device_bdaddr; ++ char *master_bdaddr; ++ int ret = 0; ++ ++ master_bdaddr = peripheral->get_master_bdaddr(fd); ++ if (master_bdaddr == NULL) { ++ DBG("Failed to get the Old master Bluetooth address from the device"); ++ return -EPERM; ++ } ++ ++ /* Only set the master bdaddr when needed, this is how the PS3 does ++ * it, perhaps to avoid unnecessary writes to some eeprom. ++ */ ++ if (g_strcmp0(master_bdaddr, adapter_bdaddr) != 0) { ++ DBG("Old master Bluetooth address was: %s", master_bdaddr); ++ ret = peripheral->set_master_bdaddr(fd, adapter_bdaddr); ++ if (ret < 0) { ++ DBG("Failed to set the master Bluetooth address"); ++ free(master_bdaddr); ++ return ret; ++ } ++ } ++ ++ device_bdaddr = peripheral->get_device_bdaddr(fd); ++ if (device_bdaddr == NULL) { ++ DBG("Failed to get the Bluetooth address from the device"); ++ free(master_bdaddr); ++ return -EPERM; ++ } ++ ++ DBG("Device bdaddr %s", device_bdaddr); ++ ++ ret = create_peripheral_association(adapter_bdaddr, device_bdaddr, peripheral); ++ ++ free(device_bdaddr); ++ free(master_bdaddr); ++ return ret; ++} ++ ++static inline struct playstation_peripheral *find_playstation_peripheral(const char *hid_id) ++{ ++ unsigned int array_size = sizeof(peripherals)/sizeof(peripherals[0]); ++ unsigned int i; ++ int ret; ++ uint16_t protocol; ++ uint16_t vendor_id; ++ uint16_t product_id; ++ ++ ret = sscanf(hid_id, "%hx:%hx:%hx", &protocol, &vendor_id, &product_id); ++ if (ret != 3) { ++ error("%s:%s() Parsing HID_ID failed", ++ __FILE__, __func__); ++ return NULL; ++ } ++ ++ for (i = 0; i < array_size; i++) { ++ if (peripherals[i].vendor_id == vendor_id && ++ peripherals[i].product_id == product_id) ++ return &peripherals[i]; ++ } ++ ++ return NULL; ++} ++ ++static inline int is_usb_peripheral(const char *hid_id) ++{ ++ int ret; ++ uint16_t protocol; ++ uint16_t vendor_id; ++ uint16_t product_id; ++ ++ ret = sscanf(hid_id, "%hx:%hx:%hx", &protocol, &vendor_id, &product_id); ++ if (ret != 3) { ++ error("%s:%s() Parsing HID_ID failed", ++ __FILE__, __func__); ++ return 0; ++ } ++ ++ DBG("%hx:%hx:%hx", protocol, vendor_id, product_id); ++ return (protocol == 3); ++} ++ ++static void handle_device_plug(struct udev_device *udevice) ++{ ++ struct udev_device *hid_parent; ++ struct udev_enumerate *enumerate; ++ struct udev_list_entry *devices, *dev_list_entry; ++ const char *hid_id; ++ const char *hid_phys; ++ const char *hidraw_node; ++ unsigned char is_usb = FALSE; ++ int js_num = 0; ++ int fd; ++ struct playstation_peripheral *peripheral; ++ ++ hid_parent = udev_device_get_parent_with_subsystem_devtype(udevice, ++ "hid", NULL); ++ if (!hid_parent) { ++ error("%s:%s() cannot get parent hid device", ++ __FILE__, __func__); ++ return; ++ } ++ ++ hid_id = udev_device_get_property_value(hid_parent, "HID_ID"); ++ DBG("HID_ID: %s", hid_id); ++ ++ peripheral = find_playstation_peripheral(hid_id); ++ if (!peripheral) { ++ error("No supported peripheral found"); ++ return; ++ } ++ ++ DBG("Found a Playstation peripheral: %s", peripheral->name); ++ ++ hidraw_node = udev_device_get_devnode(udevice); ++ ++ /* looking for joysticks */ ++ hid_phys = udev_device_get_property_value(hid_parent, "HID_PHYS"); ++ ++ enumerate = udev_enumerate_new(udev_device_get_udev(udevice)); ++ udev_enumerate_add_match_sysname(enumerate, "js*"); ++ udev_enumerate_scan_devices(enumerate); ++ ++ devices = udev_enumerate_get_list_entry(enumerate); ++ udev_list_entry_foreach(dev_list_entry, devices) { ++ const char *devname; ++ struct udev_device *js_dev; ++ struct udev_device *input_parent; ++ const char *input_phys; ++ ++ devname = udev_list_entry_get_name(dev_list_entry); ++ js_dev = udev_device_new_from_syspath(udev_device_get_udev(udevice), ++ devname); ++ ++ input_parent = udev_device_get_parent_with_subsystem_devtype(js_dev, ++ "input", NULL); ++ if (!input_parent) { ++ error("%s:%s() cannot get parent input device.", ++ __FILE__, __func__); ++ continue; ++ } ++ ++ /* check this is the joystick relative to ++ * the hidraw device above */ ++ input_phys = udev_device_get_sysattr_value(input_parent, ++ "phys"); ++ if (g_strcmp0(input_phys, hid_phys) == 0) { ++ js_num = atoi(udev_device_get_sysnum(js_dev)) + 1; ++ DBG("joypad device_num: %d", js_num); ++ DBG("hidraw_node: %s", hidraw_node); ++ } ++ ++ udev_device_unref(js_dev); ++ } ++ ++ udev_enumerate_unref(enumerate); ++ ++ fd = open(hidraw_node, O_RDWR); ++ if (fd < 0) { ++ error("%s:%s() hidraw open", __FILE__, __func__); ++ return; ++ } ++ ++ is_usb = is_usb_peripheral(hid_id); ++ if (is_usb) { ++ char *adapter_bdaddr; ++ ++ adapter_bdaddr = btd_adapter_get_default_address(); ++ if (adapter_bdaddr == NULL) { ++ error("No adapters, exiting"); ++ return; ++ } ++ ++ DBG("Adapter bdaddr %s", adapter_bdaddr); ++ ++ peripheral_pair(fd, adapter_bdaddr, peripheral); ++ free(adapter_bdaddr); ++ } ++ ++ if (js_num > 0) ++ set_controller_number(fd, js_num); ++ ++ close(fd); ++} ++ ++static gboolean device_event_idle(struct udev_device *udevice) ++{ ++ handle_device_plug(udevice); ++ udev_device_unref(udevice); ++ return FALSE; ++} ++ ++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) { ++ udev_device_unref(udevice); ++ goto out; ++ } ++ ++ /* Give UDEV some time to load kernel modules */ ++ g_timeout_add_seconds(1, (GSourceFunc) device_event_idle, udevice); ++ ++out: ++ return TRUE; ++} ++ ++static int playstation_peripheral_init(void) ++{ ++ GIOChannel *channel; ++ ++ DBG("Setup Playstation peripheral plugin"); ++ ++ ctx = udev_new(); ++ monitor = udev_monitor_new_from_netlink(ctx, "udev"); ++ if (monitor == NULL) { ++ error("%s:%s() Could not get udev monitor", ++ __FILE__, __func__); ++ return -1; ++ } ++ ++ /* Listen for newly connected hidraw interfaces */ ++ udev_monitor_filter_add_match_subsystem_devtype(monitor, ++ "hidraw", 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 playstation_peripheral_exit(void) ++{ ++ DBG("Cleanup Playstation peripheral 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(playstation_peripheral, VERSION, ++ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, ++ playstation_peripheral_init, ++ playstation_peripheral_exit) +-- +1.7.10.4 + + +From 0b2c7efd2105f793170a8d0b90eaf49647315afb Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Fri, 5 Aug 2011 13:06:27 +0200 +Subject: [PATCH 4/5] XXX: plugins/playstation-peripheral: Wait for the PS + button before setting the LEDs +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +Wait for actual input events, that is PS button has been pressed, before +setting the LEDs to indicate the controller number. +This makes setting LEDs look like on the PS3. + +NOTE: This change is experimental, the logic is too simple and can fail when +multiple peripherals are handled. Don't squash it into other commits. +--- + plugins/playstation-peripheral.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/plugins/playstation-peripheral.c b/plugins/playstation-peripheral.c +index 9238e92..c7d4bdf 100644 +--- a/plugins/playstation-peripheral.c ++++ b/plugins/playstation-peripheral.c +@@ -318,8 +318,16 @@ static void handle_device_plug(struct udev_device *udevice) + free(adapter_bdaddr); + } + +- if (js_num > 0) ++ if (js_num > 0) { ++ char c; ++ ++ /* wait for events before setting leds */ ++ if (read(fd, &c, 1) != 1) ++ error("%s:%s(): read error: %s", __FILE__, __func__, ++ strerror(errno)); ++ + set_controller_number(fd, js_num); ++ } + + close(fd); + } +-- +1.7.10.4 + + +From 8e72267e7af9fb223a6089e36d627d66b66924f9 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Mon, 10 Oct 2011 22:40:49 +0200 +Subject: [PATCH 5/5] XXX Add src/bluetoothd to plugins_playstation_peripheral + dependencies +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +NOTE: this change can be useful during development when we change bluez code +but it is probably overkill for the final submission. Don't squash it into +other commits. +--- + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile.am b/Makefile.am +index a78a8ba..a14d678 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -114,6 +114,7 @@ include Makefile.plugins + + if PLAYSTATION_PERIPHERAL_PLUGIN + plugin_LTLIBRARIES += plugins/playstation-peripheral.la ++plugins_playstation_peripheral_la_DEPENDENCIES = src/bluetoothd + plugins_playstation_peripheral_la_SOURCES = plugins/playstation-peripheral.c plugins/playstation-peripheral-hid.c + plugins_playstation_peripheral_la_LDFLAGS = -module -avoid-version -no-undefined @UDEV_LIBS@ + plugins_playstation_peripheral_la_CFLAGS = -fvisibility=hidden @DBUS_CFLAGS@ @GLIB_CFLAGS@ @UDEV_CFLAGS@ +-- +1.7.10.4 + diff --git a/sources b/sources index 530d5c7..f9468fd 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -fb42cb7038c380eb0e2fa208987c96ad bluez-4.101.tar.gz +b5aec2d8df0d713c577c7abf3c69dab7 bluez-5.5.tar.xz