On 12.09.15 19:53, Maksim Yevmenkin wrote: > i think it should be possible to teach bthidd to make another sdp > request to pull device id sdp record (if available). if apple mouse > answers it then it should very easy to identify it and enable all the > features.
Apples magic mouse indeed answers the SDP request for its Device ID Service Record. Find attached a first patch that adds a vendor, product and version member in the bthid_session object that is filled after both connections for the session were attached. This is done in a new function session_get_devid that issues and handles the SDP requests. There's also a new hid_initialise function, that gets a chance to take a look at those new members and initialise devices based on those information. Caveats: Only the first DevIDService record is parsed without regard for the PrimaryRecord flag. This is not necessarily correct for devices that expose multiple services. For most HID it still should be good enough and checking for multiple records and writing code to handle devices with no PrimaryRecord is way too complex for what we want to achieve. The libsdp actually issues a blocking write and, worse: a blocking read on the bluetooth connection, potentially blocking the whole bthidd until the read times out. However, since this happens after both channels were successfully established, chances are pretty good that the device will not die just when we send the request. Depending on lingual preferences, you might want to rename initialise to initialize. Comments on the patch are appreciated. I will now go on and blatantly rip off Iain Hibberts code from the NetBSD driver to make use of what the mouse sends me. Regards, erdgeist
diff -ur bthidd/Makefile /usr/src/usr.sbin/bluetooth/bthidd/Makefile --- bthidd/Makefile 2015-08-12 16:21:36.000000000 +0200 +++ /usr/src/usr.sbin/bluetooth/bthidd/Makefile 2015-09-14 01:23:58.745842317 +0200 @@ -11,7 +11,7 @@ DEBUG_FLAGS= -g DPADD= ${LIBBLUETOOTH} ${LIBUSBHID} -LDADD= -lbluetooth -lusbhid +LDADD= -lbluetooth -lusbhid -lsdp NO_WMISSING_VARIABLE_DECLARATIONS= diff -ur bthidd/bthidd.h /usr/src/usr.sbin/bluetooth/bthidd/bthidd.h --- bthidd/bthidd.h 2015-08-12 16:21:36.000000000 +0200 +++ /usr/src/usr.sbin/bluetooth/bthidd/bthidd.h 2015-09-14 01:20:49.863880887 +0200 @@ -61,6 +61,9 @@ int32_t intr; /* interrupt channel */ int32_t vkbd; /* virual keyboard */ bdaddr_t bdaddr;/* remote bdaddr */ + uint16_t vendor;/* remote vendor id */ + uint16_t product;/*remote product id */ + uint16_t version;/*remote version id */ uint16_t state; /* session state */ #define CLOSED 0 #define W4CTRL 1 @@ -84,8 +87,10 @@ bthid_session_p session_open (bthid_server_p srv, hid_device_p const d); bthid_session_p session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr); bthid_session_p session_by_fd (bthid_server_p srv, int32_t fd); +void session_get_devid(bthid_session_p s); void session_close (bthid_session_p s); +void hid_initialise (bthid_session_p s); int32_t hid_control (bthid_session_p s, uint8_t *data, int32_t len); int32_t hid_interrupt (bthid_session_p s, uint8_t *data, int32_t len); diff -ur bthidd/hid.c /usr/src/usr.sbin/bluetooth/bthidd/hid.c --- bthidd/hid.c 2015-08-12 16:21:36.000000000 +0200 +++ /usr/src/usr.sbin/bluetooth/bthidd/hid.c 2015-09-14 01:43:48.644754678 +0200 @@ -49,6 +49,19 @@ #include "kbd.h" /* + * Probe for per-device initialisation + */ +void +hid_initialise(bthid_session_p s) +{ + /* Magic report to enable trackpad on Apple's Magic Mouse + static uint8_t rep[] = { 0x53, 0xd7, 0x01 }; + if(s->vendor == 0x5ac && s->product == 0x30d ) + write(s->ctrl, rep, 3 ); + */ +} + +/* * Process data from control channel */ diff -ur bthidd/server.c /usr/src/usr.sbin/bluetooth/bthidd/server.c --- bthidd/server.c 2015-08-12 16:21:36.000000000 +0200 +++ /usr/src/usr.sbin/bluetooth/bthidd/server.c 2015-09-14 01:44:12.843765049 +0200 @@ -286,6 +286,12 @@ srv->maxfd = s->vkbd; } + /* Get VendorID and ProductID after both channels are established */ + if (s->state == OPEN) { + session_get_devid(s); + hid_initialise(s); + } + return (0); } diff -ur bthidd/session.c /usr/src/usr.sbin/bluetooth/bthidd/session.c --- bthidd/session.c 2015-08-12 16:21:36.000000000 +0200 +++ /usr/src/usr.sbin/bluetooth/bthidd/session.c 2015-09-14 01:50:19.862726418 +0200 @@ -36,6 +36,7 @@ #include <bluetooth.h> #include <errno.h> #include <fcntl.h> +#include <sdp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -61,7 +62,7 @@ if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL) return (NULL); - s->srv = srv; + s->srv = srv; memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr)); s->ctrl = -1; s->intr = -1; @@ -80,6 +81,7 @@ s->vkbd = -1; s->state = CLOSED; + s->vendor = s->product = s->version = 0; s->keys1 = bit_alloc(kbd_maxkey()); if (s->keys1 == NULL) { @@ -138,6 +140,89 @@ } /* + * Get Device ID Service Record for session + + Hard coded attibute IDs taken from the + DEVICE IDENTIFICATION PROFILE SPECIFICATION V13 p.12 + */ + +#define SDP_DEVICE_ID_SERVICE_ATTR_VENDORID 0x0201 +#define SDP_DEVICE_ID_SERVICE_ATTR_PRODUCTID 0x0202 +#define SDP_DEVICE_ID_SERVICE_ATTR_VERSION 0x0203 +#define SDP_DEVICE_ID_RANGE SDP_ATTR_RANGE( \ + SDP_DEVICE_ID_SERVICE_ATTR_VENDORID, SDP_DEVICE_ID_SERVICE_ATTR_VERSION ) + +void +session_get_devid(bthid_session_p s) +{ + sdp_attr_t val[3]; + uint8_t buf[16]; + uint16_t devid_servrec_uuid = SDP_SERVICE_CLASS_PNP_INFORMATION; + uint32_t devid_servrec_attr_range = SDP_DEVICE_ID_RANGE; + uint32_t type; + void *xs; + uint8_t *v; + int i; + + assert(s != NULL); + assert(s->state == OPEN); + + xs = sdp_open(NG_HCI_BDADDR_ANY, &s->bdaddr); + if (!xs) + return; + + /* Initialise return array */ + for (i=0; i<3; ++i) { + val[i].flags = SDP_ATTR_INVALID; + val[i].attr = 0; + val[i].value = buf + i*4; + val[i].vlen = 4; /* Max size should be 3 */ + } + + /* Getting only the first set of attributes, assuming the + primary record to come first. TODO. */ + if (sdp_search(xs, 1, &devid_servrec_uuid, + 1, &devid_servrec_attr_range, + 3, val) != 0 ) { + sdp_close(xs); + return; + } + + + /* If search is successful, scan through return vals */ + for (i=0; i<3; ++i) { + if (val[i].flags == SDP_ATTR_INVALID ) + continue; + + /* Expecting tag + uint16_t on all 3 attributes */ + if (val[i].vlen != 3) + continue; + + /* Make sure, we're reading a uint16_t */ + v = val[i].value; + SDP_GET8(type, v); + if (type != SDP_DATA_UINT16 ) + continue; + + switch (val[i].attr) { + case SDP_DEVICE_ID_SERVICE_ATTR_VENDORID: + SDP_GET16(s->vendor, v); + break; + case SDP_DEVICE_ID_SERVICE_ATTR_PRODUCTID: + SDP_GET16(s->product, v); + break; + case SDP_DEVICE_ID_SERVICE_ATTR_VERSION: + SDP_GET16(s->version, v); + break; + default: + break; + } + } + + sdp_close(xs); +} + +/* * Close session */
_______________________________________________ freebsd-bluetooth@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-bluetooth To unsubscribe, send any mail to "freebsd-bluetooth-unsubscr...@freebsd.org"