--- bluez-5.18/Makefile.am.playstation~ 2014-03-25 21:53:41.000000000 +0100 +++ bluez-5.18/Makefile.am 2014-05-06 22:13:18.967174167 +0200 @@ -115,6 +115,15 @@ builtin_nodist = 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@ +plugins_playstation_peripheral_la_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/lib +endif + if MAINTAINER_MODE plugin_LTLIBRARIES += plugins/external-dummy.la plugins_external_dummy_la_SOURCES = plugins/external-dummy.c --- bluez-5.18/configure.ac.playstation~ 2014-04-12 12:13:29.000000000 +0200 +++ bluez-5.18/configure.ac 2014-05-06 22:09:30.225172158 +0200 @@ -221,6 +221,16 @@ AC_ARG_ENABLE(sixaxis, AC_HELP_STRING([- AM_CONDITIONAL(SIXAXIS, test "${enable_sixaxis}" = "yes" && test "${enable_udev}" != "no") +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 --- bluez-5.18/plugins/playstation-peripheral-hid.c.playstation~ 2014-05-06 22:09:30.225172158 +0200 +++ bluez-5.18/plugins/playstation-peripheral-hid.c 2014-05-06 22:09:30.225172158 +0200 @@ -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); +} --- bluez-5.18/plugins/playstation-peripheral-hid.h.playstation~ 2014-05-06 22:09:30.226172158 +0200 +++ bluez-5.18/plugins/playstation-peripheral-hid.h 2014-05-06 22:09:30.226172158 +0200 @@ -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 */ --- bluez-5.18/plugins/playstation-peripheral.c.playstation~ 2014-05-06 22:09:30.227172158 +0200 +++ bluez-5.18/plugins/playstation-peripheral.c 2014-05-06 22:09:30.227172158 +0200 @@ -0,0 +1,409 @@ +/* + * 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) { + 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); +} + +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) --- bluez-5.18/src/adapter.c.playstation~ 2014-04-12 12:13:29.000000000 +0200 +++ bluez-5.18/src/adapter.c 2014-05-06 22:09:30.229172158 +0200 @@ -240,6 +240,23 @@ struct btd_adapter *btd_adapter_get_defa 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(btd_adapter_get_address(adapter), str); + return str; +} + bool btd_adapter_is_default(struct btd_adapter *adapter) { if (!adapter) @@ -6787,3 +6804,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 = btd_adapter_get_device(adapter, &dst, BDADDR_BREDR); + if (device == NULL) { + DBG("Failed to get the device"); + ret = -ENODEV; + goto out; + } + + if (name) + btd_device_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); + + btd_device_set_temporary(device, FALSE); + + if (trusted) + btd_device_set_trusted(device, TRUE); +out: + return ret; +} --- bluez-5.18/src/adapter.h.playstation~ 2014-03-25 21:53:42.000000000 +0100 +++ bluez-5.18/src/adapter.h 2014-05-06 22:09:30.230172158 +0200 @@ -39,6 +39,7 @@ struct btd_adapter; struct btd_device; 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); @@ -199,3 +200,14 @@ gboolean btd_adapter_check_oob_handler(s 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 *btd_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);