2015-04-08 20:51:28

by Szymon Janc

[permalink] [raw]
Subject: [RFC v2 0/3] sixaxis: Improved support for DualShock 3 clones

Hi,

Some DualShock3 clones (eg ShanWan) were reported to not provide valid SDP
record required by HID profile. Due to this those failed to work with
current BlueZ sixaxis code (ie no input device were created).

This small serie is an attempt to extend DS3 support also with those
misbehaving clones. Idea is that we can provide fixed SDP recrod for devices
that use valid PID/VID and skip SDP search.

In this version SDP is kept in sixaxis plugin and provided via
btd_device_set_record instead of SDP search. Nice addition is that
sixaxis specific code is no longer needed in input server.

This makes code similar to how original Fedora sixaxis plugin worked
as suggested in previous review round.

I tested this with genuine DS3 and it seems to work OK. Testing with
clones is stil required though.

@Alex
Testing with Navigation Controller is also needed ie if SDP record
is same as with DS3 or if we need dedicated one.

BR
Szymon Janc


Szymon Janc (3):
core/device: Add support for setting SDP record
sixaxis: Provide DualShock 3 SDP record while adding new device
profiles/input: Remove sixaxis specific code

Makefile.plugins | 1 +
plugins/sixaxis.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++
profiles/input/server.c | 89 +-------------------------
src/device.c | 31 +++++++++
src/device.h | 3 +
5 files changed, 203 insertions(+), 87 deletions(-)

--
2.1.4



2015-04-08 20:51:31

by Szymon Janc

[permalink] [raw]
Subject: [RFC v2 3/3] profiles/input: Remove sixaxis specific code

Sixaxis devices now have provides SDP record while being created.
There is no need to punch sixaxis holes in input code anymore.
---
profiles/input/server.c | 89 ++-----------------------------------------------
1 file changed, 2 insertions(+), 87 deletions(-)

diff --git a/profiles/input/server.c b/profiles/input/server.c
index eb3fcf8..43733ea 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -67,85 +67,6 @@ static int server_cmp(gconstpointer s, gconstpointer user_data)
return bacmp(&server->src, src);
}

-struct sixaxis_data {
- GIOChannel *chan;
- uint16_t psm;
-};
-
-static void sixaxis_sdp_cb(struct btd_device *dev, int err, void *user_data)
-{
- struct sixaxis_data *data = user_data;
- const bdaddr_t *src;
-
- DBG("err %d (%s)", err, strerror(-err));
-
- if (err < 0)
- goto fail;
-
- src = btd_adapter_get_address(device_get_adapter(dev));
-
- if (input_device_set_channel(src, device_get_address(dev), data->psm,
- data->chan) < 0)
- goto fail;
-
- g_io_channel_unref(data->chan);
- g_free(data);
-
- return;
-
-fail:
- g_io_channel_shutdown(data->chan, TRUE, NULL);
- g_io_channel_unref(data->chan);
- g_free(data);
-}
-
-static void sixaxis_browse_sdp(const bdaddr_t *src, const bdaddr_t *dst,
- GIOChannel *chan, uint16_t psm)
-{
- struct btd_device *device;
- struct sixaxis_data *data;
-
- device = btd_adapter_find_device(adapter_find(src), dst, BDADDR_BREDR);
- if (!device)
- return;
-
- data = g_new0(struct sixaxis_data, 1);
- data->chan = g_io_channel_ref(chan);
- data->psm = psm;
-
- if (psm == L2CAP_PSM_HIDP_CTRL)
- device_discover_services(device);
-
- device_wait_for_svc_complete(device, sixaxis_sdp_cb, data);
-}
-
-static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
-{
- struct btd_device *device;
- uint16_t vid, pid;
-
- device = btd_adapter_find_device(adapter_find(src), dst, BDADDR_BREDR);
- if (!device)
- return false;
-
- vid = btd_device_get_vendor(device);
- pid = btd_device_get_product(device);
-
- /* DualShock 3 */
- if (vid == 0x054c && pid == 0x0268)
- return true;
-
- /* DualShock 4 */
- if (vid == 0x054c && pid == 0x05c4)
- return true;
-
- /* Navigation Controller */
- if (vid == 0x054c && pid == 0x042f)
- return true;
-
- return false;
-}
-
static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
{
uint16_t psm;
@@ -178,11 +99,6 @@ static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
if (ret == 0)
return;

- if (ret == -ENOENT && dev_is_sixaxis(&src, &dst)) {
- sixaxis_browse_sdp(&src, &dst, chan, psm);
- return;
- }
-
error("Refusing input device connect: %s (%d)", strerror(-ret), -ret);

/* Send unplug virtual cable to unknown devices */
@@ -207,8 +123,7 @@ static void auth_callback(DBusError *derr, void *user_data)
goto reject;
}

- if (!input_device_exists(&server->src, &confirm->dst) &&
- !dev_is_sixaxis(&server->src, &confirm->dst))
+ if (!input_device_exists(&server->src, &confirm->dst))
return;

if (!bt_io_accept(confirm->io, connect_event_cb, server, NULL, &err)) {
@@ -259,7 +174,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
goto drop;
}

- if (!input_device_exists(&src, &dst) && !dev_is_sixaxis(&src, &dst)) {
+ if (!input_device_exists(&src, &dst)) {
error("Refusing connection from %s: unknown device", addr);
goto drop;
}
--
2.1.4


2015-04-08 20:51:30

by Szymon Janc

[permalink] [raw]
Subject: [RFC v2 2/3] sixaxis: Provide DualShock 3 SDP record while adding new device

This allows to skip SDP search for DualShock 3 devices. Since some
DS3 clones were reported to not provide any SDP record this should
allow to operate them.
---
Makefile.plugins | 1 +
plugins/sixaxis.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 167 insertions(+)

diff --git a/Makefile.plugins b/Makefile.plugins
index 52b51c5..9425c0a 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -116,4 +116,5 @@ plugins_sixaxis_la_SOURCES = plugins/sixaxis.c
plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
-no-undefined @UDEV_LIBS@
plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden @UDEV_CFLAGS@
+plugins_sixaxis_la_LIBADD = lib/libbluetooth-internal.la
endif
diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index fcc93bc..c930dd7 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -40,6 +40,7 @@

#include "lib/bluetooth.h"
#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
#include "lib/uuid.h"

#include "src/adapter.h"
@@ -255,6 +256,170 @@ out:
return FALSE;
}

+static sdp_record_t *get_sdp_record(void)
+{
+ sdp_record_t *record;
+ uint16_t hid_release, hid_parser, version, timeout;
+ uint8_t sdp_disable, battery, remote_wakeup, norm_connect, boot_device;
+ uint8_t subclass, country, virtual_cable, reconnect;
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[3];
+ sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
+ uint8_t dtd = SDP_UINT16;
+ uint8_t dtd2 = SDP_UINT8;
+ uint8_t dtd_data = SDP_TEXT_STR8;
+ void *dtds[2];
+ void *values[2];
+ void *dtds2[2];
+ void *values2[2];
+ int leng[2];
+ uint8_t hid_spec_type = 0x22;
+ uint16_t hid_attr_lang[] = { 0x409, 0x100 };
+ static const uint16_t ctrl = 0x11;
+ static const uint16_t intr = 0x13;
+ uint8_t hid_spec[] = {
+ 0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02, 0x85, 0x01,
+ 0x75, 0x08, 0x95, 0x01, 0x15, 0x00, 0x26, 0xff, 0x00, 0x81,
+ 0x03, 0x75, 0x01, 0x95, 0x13, 0x15, 0x00, 0x25, 0x01, 0x35,
+ 0x00, 0x45, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81,
+ 0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff, 0x81, 0x03,
+ 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 0x01, 0x09, 0x01, 0xa1,
+ 0x00, 0x75, 0x08, 0x95, 0x04, 0x35, 0x00, 0x46, 0xff, 0x00,
+ 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02,
+ 0xc0, 0x05, 0x01, 0x75, 0x08, 0x95, 0x27, 0x09, 0x01, 0x81,
+ 0x02, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0x91, 0x02, 0x75,
+ 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02,
+ 0x85, 0x02, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02,
+ 0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95, 0x30, 0x09,
+ 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0xef, 0x75, 0x08,
+ 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xc0, 0x00
+ };
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_add_lang_attr(record);
+
+ sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &hidkb_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HID_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ /* protocols */
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &ctrl);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ /* additional protocols */
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &intr);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_add_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Wireless Controller",
+ "Sony Computer Entertainment",
+ "Wireless Controller");
+
+ hid_release = 0x0100;
+ sdp_attr_add_new(record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER, SDP_UINT16,
+ &hid_release);
+
+ hid_parser = 0x0100;
+ sdp_attr_add_new(record, SDP_ATTR_HID_PARSER_VERSION, SDP_UINT16,
+ &hid_parser);
+
+ subclass = 0x00;
+ sdp_attr_add_new(record, SDP_ATTR_HID_DEVICE_SUBCLASS, SDP_UINT8,
+ &subclass);
+
+ country = 0x21;
+ sdp_attr_add_new(record, SDP_ATTR_HID_COUNTRY_CODE, SDP_UINT8,
+ &country);
+
+ virtual_cable = 0x01;
+ sdp_attr_add_new(record, SDP_ATTR_HID_VIRTUAL_CABLE, SDP_BOOL,
+ &virtual_cable);
+
+ reconnect = 0x01;
+ sdp_attr_add_new(record, SDP_ATTR_HID_RECONNECT_INITIATE, SDP_BOOL,
+ &reconnect);
+
+ dtds[0] = &dtd2;
+ values[0] = &hid_spec_type;
+ dtds[1] = &dtd_data;
+ values[1] = hid_spec;
+ leng[0] = 0;
+ leng[1] = sizeof(hid_spec);
+ hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
+ hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
+ sdp_attr_add(record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
+
+ dtds2[0] = &dtd;
+ values2[0] = &hid_attr_lang[0];
+ dtds2[1] = &dtd;
+ values2[1] = &hid_attr_lang[1];
+ lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
+ lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
+ sdp_attr_add(record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
+
+ sdp_disable = 0x00;
+ sdp_attr_add_new(record, SDP_ATTR_HID_SDP_DISABLE, SDP_BOOL,
+ &sdp_disable);
+
+ battery = 0x01;
+ sdp_attr_add_new(record, SDP_ATTR_HID_BATTERY_POWER, SDP_BOOL,
+ &battery);
+
+ remote_wakeup = 0x01;
+ sdp_attr_add_new(record, SDP_ATTR_HID_REMOTE_WAKEUP, SDP_BOOL,
+ &remote_wakeup);
+
+ version = 0x0100;
+ sdp_attr_add_new(record, SDP_ATTR_HID_PROFILE_VERSION, SDP_UINT16,
+ &version);
+
+ timeout = 0x3e80;
+ sdp_attr_add_new(record, SDP_ATTR_HID_SUPERVISION_TIMEOUT, SDP_UINT16,
+ &timeout);
+
+ norm_connect = 0x00;
+ sdp_attr_add_new(record, SDP_ATTR_HID_NORMALLY_CONNECTABLE, SDP_BOOL,
+ &norm_connect);
+
+ boot_device = 0x00;
+ sdp_attr_add_new(record, SDP_ATTR_HID_BOOT_DEVICE, SDP_BOOL,
+ &boot_device);
+
+ return record;
+}
+
static bool setup_device(int fd, int index, struct btd_adapter *adapter)
{
char device_addr[18], master_addr[18], adapter_addr[18];
@@ -303,6 +468,7 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)
btd_device_set_pnpid(device, devices[index].source, devices[index].vid,
devices[index].pid, devices[index].version);
btd_device_set_temporary(device, false);
+ btd_device_set_record(device, HID_UUID, get_sdp_record());

return true;
}
--
2.1.4


2015-04-08 20:51:29

by Szymon Janc

[permalink] [raw]
Subject: [RFC v2 1/3] core/device: Add support for setting SDP record

This allows to set SDP record for device without resolving services
over SDP. After SDP is provided profiles are probed.
---
src/device.c | 31 +++++++++++++++++++++++++++++++
src/device.h | 3 +++
2 files changed, 34 insertions(+)

diff --git a/src/device.c b/src/device.c
index 91dea27..e5cf362 100644
--- a/src/device.c
+++ b/src/device.c
@@ -5293,6 +5293,37 @@ static sdp_list_t *read_device_records(struct btd_device *device)
return recs;
}

+void btd_device_set_record(struct btd_device *device, const char *uuid,
+ sdp_record_t *rec)
+{
+ /* This API is only used for BR/EDR */
+ struct bearer_state *state = &device->bredr_state;
+ struct browse_req *req;
+ sdp_list_t *recs = NULL;
+
+ if (!rec)
+ return;
+
+ req = browse_request_new(device, NULL);
+ if (!req)
+ return;
+
+ recs = sdp_list_append(recs, rec);
+ update_bredr_services(req, recs);
+ sdp_list_free(recs, NULL);
+
+ device->svc_refreshed = true;
+ state->svc_resolved = true;
+
+ device_probe_profiles(device, req->profiles_added);
+
+ /* Propagate services changes */
+ g_dbus_emit_property_changed(dbus_conn, req->device->path,
+ DEVICE_INTERFACE, "UUIDs");
+
+ device_svc_resolved(device, device->bdaddr_type, 0);
+}
+
const sdp_record_t *btd_device_get_record(struct btd_device *device,
const char *uuid)
{
diff --git a/src/device.h b/src/device.h
index 9e86469..7e9a369 100644
--- a/src/device.h
+++ b/src/device.h
@@ -62,6 +62,9 @@ struct device_addr_type {
int device_addr_type_cmp(gconstpointer a, gconstpointer b);
GSList *btd_device_get_uuids(struct btd_device *device);
void device_probe_profiles(struct btd_device *device, GSList *profiles);
+
+void btd_device_set_record(struct btd_device *device, const char *uuid,
+ sdp_record_t *rec);
const sdp_record_t *btd_device_get_record(struct btd_device *device,
const char *uuid);
struct gatt_primary *btd_device_get_primary(struct btd_device *device,
--
2.1.4