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 even if SDP search failed.
This was tested only with genuine controller (with crippled SDP code) so
before I consider this code ready for inclusion it needs to be tested
on clone devices.
BR
Szymon
Szymon Janc (2):
core/device: Add support for setting SDP record
profiles/input: Add support for SDP fallback for DualShock 3 clones
profiles/input/server.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++--
src/device.c | 37 ++++++++++
src/device.h | 3 +
3 files changed, 224 insertions(+), 7 deletions(-)
--
2.1.4
On Mon, 2015-03-09 at 14:37 +0100, Szymon Janc wrote:
> Hi Antonio,
>
> On Monday 09 of March 2015 12:21:08 Antonio Ospite wrote:
> > On Sun, 8 Mar 2015 17:08:30 +0100
> > Szymon Janc <[email protected]> wrote:
> >
> > > Some DualShock 3 clones were reported to not provide any SDP
> > > record. In such case provide fallback SDP record (based on
> > > genuine DS3 record) and retry setting input device channels
> > > before disconnecting.
> >
> > Hi Szymon,
> >
> > I guess this can't be done in the sixaxis plugin, right?
>
> Unfortunately not. There would have to be some sort of callbacks
> from input
> to handle this from plugin. But if you come up with some nice
> solution I'd
> review it gladly :)
>
> Maybe we could modify code to always provide those on USB plug and
> then never do
> reverse SDP when sixaxis device is detected... I'd have to think
> about that :)
That's what the original version of the sixaxis patch for BlueZ (the
one that shipped only in Fedora for a long while) did.
When you create the BlueZ device setup by plugging in the pad, shove
the SDP record in the local cache as well.
In the worst case, people will need to remove the device from the
Bluetooth settings, and plug it back in via USB.
Hi Antonio,
On Monday 09 of March 2015 12:21:08 Antonio Ospite wrote:
> On Sun, 8 Mar 2015 17:08:30 +0100
> Szymon Janc <[email protected]> wrote:
>
> > Some DualShock 3 clones were reported to not provide any SDP record.
> > In such case provide fallback SDP record (based on genuine DS3 record)
> > and retry setting input device channels before disconnecting.
>
> Hi Szymon,
>
> I guess this can't be done in the sixaxis plugin, right?
Unfortunately not. There would have to be some sort of callbacks from input
to handle this from plugin. But if you come up with some nice solution I'd
review it gladly :)
Maybe we could modify code to always provide those on USB plug and then never do
reverse SDP when sixaxis device is detected... I'd have to think about that :)
> I have a question, below.
>
> > ---
> > profiles/input/server.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++--
> > 1 file changed, 184 insertions(+), 7 deletions(-)
> >
> > diff --git a/profiles/input/server.c b/profiles/input/server.c
> > index eb3fcf8..4b7b1e1 100644
> > --- a/profiles/input/server.c
> > +++ b/profiles/input/server.c
> > @@ -35,6 +35,7 @@
> > #include "lib/bluetooth.h"
> > #include "lib/sdp.h"
> > #include "lib/uuid.h"
> > +#include "lib/sdp_lib.h"
> >
> > #include "src/log.h"
> > #include "src/uuid-helper.h"
> > @@ -72,29 +73,205 @@ struct sixaxis_data {
> > uint16_t psm;
> > };
> >
> > +static sdp_record_t *get_sixaxis_record(struct btd_device *device)
> > +{
> [...]
> > + 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
> > + };
>
> As you may know, the kernel overrides the HID report descriptor in the
> hid-sony driver.
>
> Is the descriptor above only to be considered as the _default_ HID
> report description?
>
> I ask to confirm that this would not need to be changed in case the
> overriding HID descriptor in hid-sony changed once again.
Those are just copied from genuine DualShock3 SDP record.
> Thanks,
> Antonio
>
>
--
Best regards,
Szymon Janc
On Sun, 8 Mar 2015 17:08:30 +0100
Szymon Janc <[email protected]> wrote:
> Some DualShock 3 clones were reported to not provide any SDP record.
> In such case provide fallback SDP record (based on genuine DS3 record)
> and retry setting input device channels before disconnecting.
Hi Szymon,
I guess this can't be done in the sixaxis plugin, right?
I have a question, below.
> ---
> profiles/input/server.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 184 insertions(+), 7 deletions(-)
>
> diff --git a/profiles/input/server.c b/profiles/input/server.c
> index eb3fcf8..4b7b1e1 100644
> --- a/profiles/input/server.c
> +++ b/profiles/input/server.c
> @@ -35,6 +35,7 @@
> #include "lib/bluetooth.h"
> #include "lib/sdp.h"
> #include "lib/uuid.h"
> +#include "lib/sdp_lib.h"
>
> #include "src/log.h"
> #include "src/uuid-helper.h"
> @@ -72,29 +73,205 @@ struct sixaxis_data {
> uint16_t psm;
> };
>
> +static sdp_record_t *get_sixaxis_record(struct btd_device *device)
> +{
[...]
> + 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
> + };
As you may know, the kernel overrides the HID report descriptor in the
hid-sony driver.
Is the descriptor above only to be considered as the _default_ HID
report description?
I ask to confirm that this would not need to be changed in case the
overriding HID descriptor in hid-sony changed once again.
Thanks,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
Some DualShock 3 clones were reported to not provide any SDP record.
In such case provide fallback SDP record (based on genuine DS3 record)
and retry setting input device channels before disconnecting.
---
profiles/input/server.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 184 insertions(+), 7 deletions(-)
diff --git a/profiles/input/server.c b/profiles/input/server.c
index eb3fcf8..4b7b1e1 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -35,6 +35,7 @@
#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/uuid.h"
+#include "lib/sdp_lib.h"
#include "src/log.h"
#include "src/uuid-helper.h"
@@ -72,29 +73,205 @@ struct sixaxis_data {
uint16_t psm;
};
+static sdp_record_t *get_sixaxis_record(struct btd_device *device)
+{
+ sdp_record_t *record;
+ uint16_t vid, pid, 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
+ };
+
+ vid = btd_device_get_vendor(device);
+ pid = btd_device_get_product(device);
+
+ /* only for DualShock 3 clones */
+ if (vid != 0x054c || pid != 0x0268)
+ return NULL;
+
+ 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 void sixaxis_sdp_cb(struct btd_device *dev, int err, void *user_data)
{
+ const bdaddr_t *src = btd_adapter_get_address(device_get_adapter(dev));
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));
+ goto fallback;
if (input_device_set_channel(src, device_get_address(dev), data->psm,
data->chan) < 0)
- goto fail;
+ goto fallback;
g_io_channel_unref(data->chan);
g_free(data);
return;
-fail:
- g_io_channel_shutdown(data->chan, TRUE, NULL);
+fallback:
+ DBG("SDP search failed, attempting fallback");
+
+ btd_device_set_record(dev, HID_UUID, get_sixaxis_record(dev));
+
+ if (input_device_set_channel(src, device_get_address(dev),
+ data->psm, data->chan) < 0)
+ g_io_channel_shutdown(data->chan, TRUE, NULL);
+
g_io_channel_unref(data->chan);
g_free(data);
}
--
2.1.4
This allows to set SDP record for device without resolving services
over SDP.
---
src/device.c | 37 +++++++++++++++++++++++++++++++++++++
src/device.h | 3 +++
2 files changed, 40 insertions(+)
diff --git a/src/device.c b/src/device.c
index 9e23c19..6e896ba 100644
--- a/src/device.c
+++ b/src/device.c
@@ -5272,6 +5272,43 @@ 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);
+
+ if (device->tmp_records) {
+ if (find_record_in_list(device->tmp_records, uuid))
+ return;
+
+ sdp_list_free(device->tmp_records,
+ (sdp_free_func_t) sdp_record_free);
+ }
+
+ device->tmp_records = sdp_list_append(NULL, rec);
+
+ device->svc_refreshed = true;
+ state->svc_resolved = true;
+
+ btd_device_add_uuid(device, uuid);
+
+ 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 8edd0df..f42b3f4 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