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 cae43d9..2c2385d 100644 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -118,4 +118,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 50db6c1..782a89f 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" @@ -257,6 +258,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]; @@ -316,6 +481,7 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter) devices[index].version); btd_device_set_temporary(device, false); + btd_device_set_record(device, HID_UUID, get_sdp_record()); return true; } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html