Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137238431
D3702.id8902.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D3702.id8902.diff
View Options
Index: /usr/src/usr.sbin/bluetooth/bthidcontrol/sdp.c
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidcontrol/sdp.c
+++ /usr/src/usr.sbin/bluetooth/bthidcontrol/sdp.c
@@ -46,7 +46,20 @@
static int32_t hid_sdp_parse_hid_descriptor (sdp_attr_p a);
static int32_t hid_sdp_parse_boolean (sdp_attr_p a);
+/*
+ * Hard coded attibute IDs taken from the
+ * DEVICE IDENTIFICATION PROFILE SPECIFICATION V13 p.12
+ */
+
+#define SDP_ATTR_DEVICE_ID_SERVICE_VENDORID 0x0201
+#define SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID 0x0202
+#define SDP_ATTR_DEVICE_ID_SERVICE_VERSION 0x0203
+#define SDP_ATTR_DEVICE_ID_RANGE SDP_ATTR_RANGE( \
+ SDP_ATTR_DEVICE_ID_SERVICE_VENDORID, SDP_ATTR_DEVICE_ID_SERVICE_VERSION )
+
static uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
+static uint16_t service_devid = SDP_SERVICE_CLASS_PNP_INFORMATION;
+static uint32_t attrs_devid = SDP_ATTR_DEVICE_ID_RANGE;
static uint32_t attrs[] = {
SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
@@ -84,27 +97,34 @@
return (((e) == 0)? 0 : -1); \
}
+static void
+hid_init_return_values() {
+ int i;
+ for (i = 0; i < nvalues; i ++) {
+ values[i].flags = SDP_ATTR_INVALID;
+ values[i].attr = 0;
+ values[i].vlen = sizeof(buffer[i]);
+ values[i].value = buffer[i];
+ }
+}
+
static int32_t
hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
{
void *ss = NULL;
- uint8_t *hid_descriptor = NULL;
+ uint8_t *hid_descriptor = NULL, *v;
int32_t i, control_psm = -1, interrupt_psm = -1,
reconnect_initiate = -1,
normally_connectable = 0, battery_power = 0,
- hid_descriptor_length = -1;
+ hid_descriptor_length = -1, type;
+ int16_t vendor_id = 0, product_id = 0, version = 0;
if (local == NULL)
local = NG_HCI_BDADDR_ANY;
if (hd == NULL)
hid_sdp_query_exit(EINVAL);
- for (i = 0; i < nvalues; i ++) {
- values[i].flags = SDP_ATTR_INVALID;
- values[i].attr = 0;
- values[i].vlen = sizeof(buffer[i]);
- values[i].value = buffer[i];
- }
+ hid_init_return_values();
if ((ss = sdp_open(local, &hd->bdaddr)) == NULL)
hid_sdp_query_exit(ENOMEM);
@@ -113,9 +133,6 @@
if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0)
hid_sdp_query_exit(sdp_error(ss));
- sdp_close(ss);
- ss = NULL;
-
for (i = 0; i < nvalues; i ++) {
if (values[i].flags != SDP_ATTR_OK)
continue;
@@ -150,11 +167,51 @@
}
}
+ hid_init_return_values();
+
+ if (sdp_search(ss, 1, &service_devid, 1, &attrs_devid, nvalues, values) != 0)
+ hid_sdp_query_exit(sdp_error(ss));
+
+ sdp_close(ss);
+ ss = NULL;
+
+ /* If search is successful, scan through return vals */
+ for (i = 0; i < 3; i ++ ) {
+ if (values[i].flags == SDP_ATTR_INVALID )
+ continue;
+
+ /* Expecting tag + uint16_t on all 3 attributes */
+ if (values[i].vlen != 3)
+ continue;
+
+ /* Make sure, we're reading a uint16_t */
+ v = values[i].value;
+ SDP_GET8(type, v);
+ if (type != SDP_DATA_UINT16 )
+ continue;
+
+ switch (values[i].attr) {
+ case SDP_ATTR_DEVICE_ID_SERVICE_VENDORID:
+ SDP_GET16(vendor_id, v);
+ break;
+ case SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID:
+ SDP_GET16(product_id, v);
+ break;
+ case SDP_ATTR_DEVICE_ID_SERVICE_VERSION:
+ SDP_GET16(version, v);
+ break;
+ default:
+ break;
+ }
+ }
+
if (control_psm == -1 || interrupt_psm == -1 ||
reconnect_initiate == -1 ||
hid_descriptor == NULL || hid_descriptor_length == -1)
hid_sdp_query_exit(ENOATTR);
-
+ hd->vendor_id = vendor_id;
+ hd->product_id = product_id;
+ hd->version = version;
hd->control_psm = control_psm;
hd->interrupt_psm = interrupt_psm;
hd->reconnect_initiate = reconnect_initiate? 1 : 0;
Index: /usr/src/usr.sbin/bluetooth/bthidd/bthid_config.h
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/bthid_config.h
+++ /usr/src/usr.sbin/bluetooth/bthidd/bthid_config.h
@@ -42,6 +42,9 @@
bdaddr_t bdaddr; /* HID device BDADDR */
uint16_t control_psm; /* control PSM */
uint16_t interrupt_psm; /* interrupt PSM */
+ uint16_t vendor_id; /* primary vendor id */
+ uint16_t product_id;
+ uint16_t version;
unsigned new_device : 1;
unsigned reconnect_initiate : 1;
unsigned battery_power : 1;
Index: /usr/src/usr.sbin/bluetooth/bthidd/bthidd.h
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/bthidd.h
+++ /usr/src/usr.sbin/bluetooth/bthidd/bthidd.h
@@ -60,6 +60,7 @@
int32_t ctrl; /* control channel */
int32_t intr; /* interrupt channel */
int32_t vkbd; /* virual keyboard */
+ void *ctx; /* product specific dev state */
bdaddr_t bdaddr;/* remote bdaddr */
uint16_t state; /* session state */
#define CLOSED 0
@@ -86,6 +87,7 @@
bthid_session_p session_by_fd (bthid_server_p srv, int32_t fd);
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);
Index: /usr/src/usr.sbin/bluetooth/bthidd/bthidd.conf.sample
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/bthidd.conf.sample
+++ /usr/src/usr.sbin/bluetooth/bthidd/bthidd.conf.sample
@@ -2,6 +2,9 @@
device {
bdaddr 00:50:f2:e5:68:84;
+ vendor_id 0x0000;
+ product_id 0x0000;
+ version 0x0000;
control_psm 0x11;
interrupt_psm 0x13;
reconnect_initiate true;
@@ -24,6 +27,9 @@
device {
bdaddr 00:50:f2:e3:fb:e1;
+ vendor_id 0x0000;
+ product_id 0x0000;
+ version 0x0000;
control_psm 0x11;
interrupt_psm 0x13;
reconnect_initiate true;
Index: /usr/src/usr.sbin/bluetooth/bthidd/hid.c
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/hid.c
+++ /usr/src/usr.sbin/bluetooth/bthidd/hid.c
@@ -40,6 +40,7 @@
#include <dev/usb/usbhid.h>
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
@@ -49,6 +50,50 @@
#include "kbd.h"
/*
+ * Inoffical and unannounced report ids for Apple Mice and trackpad
+ */
+#define TRACKPAD_REPORT_ID 0x28
+#define AMM_REPORT_ID 0x29
+#define BATT_STAT_REPORT_ID 0x30
+#define BATT_STRENGTH_REPORT_ID 0x47
+#define SURFACE_REPORT_ID 0x61
+
+/*
+ * Apple magic mouse (AMM) specific device state
+ */
+#define AMM_MAX_BUTTONS 16
+struct apple_state {
+ int y [AMM_MAX_BUTTONS];
+ int button_state;
+};
+
+#define MAGIC_MOUSE(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30d))
+#define AMM_BASIC_BLOCK 5
+#define AMM_FINGER_BLOCK 8
+#define AMM_VALID_REPORT(L) (((L) >= AMM_BASIC_BLOCK) && \
+ ((L) <= 16*AMM_FINGER_BLOCK + AMM_BASIC_BLOCK) && \
+ ((L) % AMM_FINGER_BLOCK) == AMM_BASIC_BLOCK)
+#define AMM_WHEEL_SPEED 100
+
+/*
+ * Probe for per-device initialisation
+ */
+void
+hid_initialise(bthid_session_p s)
+{
+ hid_device_p hid_device = get_hid_device(&s->bdaddr);
+
+ if (hid_device && MAGIC_MOUSE(hid_device)) {
+ /* Magic report to enable trackpad on Apple's Magic Mouse */
+ static uint8_t rep[] = {0x53, 0xd7, 0x01};
+
+ if ((s->ctx = calloc(1, sizeof(struct apple_state))) == NULL)
+ return;
+ write(s->ctrl, rep, 3);
+ }
+}
+
+/*
* Process data from control channel
*/
@@ -370,6 +415,91 @@
hid_end_parse(d);
/*
+ * Apple adheres to no standards and sends reports it does
+ * not introduce in its hid descriptor for its magic mouse.
+ * Handle those reports here.
+ */
+ if (MAGIC_MOUSE(hid_device) && s->ctx) {
+ struct apple_state *c = (struct apple_state *)s->ctx;
+ int firm = 0, middle = 0;
+ int16_t v;
+
+ data++, len++; /* Chomp report_id */
+
+ if (report_id != AMM_REPORT_ID || !AMM_VALID_REPORT(len))
+ goto check_middle_button;
+
+ /*
+ * The basics. When touches are detected, no normal mouse
+ * reports are sent. Collect clicks and dx/dy
+ */
+ if (data[2] & 1)
+ mouse_butt |= 0x1;
+ if (data[2] & 2)
+ mouse_butt |= 0x4;
+
+ if ((v = data[0] + ((data[2] & 0x0C) << 6)))
+ mouse_x += ((int16_t)(v << 6)) >> 6, mevents++;
+ if ((v = data[1] + ((data[2] & 0x30) << 4)))
+ mouse_y += ((int16_t)(v << 6)) >> 6, mevents++;
+
+ /*
+ * The hard part: accumulate touch events and emulate middle
+ */
+ for (data += AMM_BASIC_BLOCK, len -= AMM_BASIC_BLOCK;
+ len >= AMM_FINGER_BLOCK;
+ data += AMM_FINGER_BLOCK, len -= AMM_FINGER_BLOCK) {
+ int x, y, z, force, id;
+
+ v = data[0] | ((data[1] & 0xf) << 8);
+ x = ((int16_t)(v << 4)) >> 4;
+
+ v = (data[1] >> 4) | (data[2] << 4);
+ y = -(((int16_t)(v << 4)) >> 4);
+
+ force = data[5] & 0x3f;
+ id = 0xf & ((data[5] >> 6) | (data[6] << 2));
+ z = (y - c->y[id]) / AMM_WHEEL_SPEED;
+
+ switch ((data[7] >> 4) & 0x7) { /* Phase */
+ case 3: /* First touch */
+ c->y[id] = y;
+ break;
+ case 4: /* Touch dragged */
+ if (z) {
+ mouse_z += z;
+ c->y[id] += z * AMM_WHEEL_SPEED;
+ mevents++;
+ }
+ break;
+ default:
+ break;
+ }
+ /* Count firm touches vs. firm+middle touches */
+ if (force >= 8 && ++firm && x > -350 && x < 350)
+ ++middle;
+ }
+
+ /*
+ * If a new click is registered by mouse and there are firm
+ * touches which are all in center, make it a middle click
+ */
+ if (mouse_butt && !c->button_state && firm && middle == firm)
+ mouse_butt = 0x2;
+
+ /*
+ * If we're still clicking and have converted the click
+ * to a middle click, keep it middle clicking
+ */
+check_middle_button:
+ if (mouse_butt && c->button_state == 0x2)
+ mouse_butt = 0x2;
+
+ if (mouse_butt != c->button_state)
+ c->button_state = mouse_butt, mevents++;
+ }
+
+ /*
* XXX FIXME Feed keyboard events into kernel.
* The code below works, bit host also needs to track
* and handle repeat.
@@ -403,7 +533,6 @@
mi.u.data.y = mouse_y;
mi.u.data.z = mouse_z;
mi.u.data.buttons = mouse_butt;
-
if (ioctl(s->srv->cons, CONS_MOUSECTL, &mi) < 0)
syslog(LOG_ERR, "Could not process mouse events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
Index: /usr/src/usr.sbin/bluetooth/bthidd/lexer.l
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/lexer.l
+++ /usr/src/usr.sbin/bluetooth/bthidd/lexer.l
@@ -50,9 +50,13 @@
hexdigit [0-9a-fA-F]
hexbyte {hexdigit}{hexdigit}?
+hexword {hexdigit}{hexdigit}?{hexdigit}?{hexdigit}?
device_word device
bdaddr_word bdaddr
+vendor_id_word vendor_id
+product_id_word product_id
+version_word version
control_psm_word control_psm
interrupt_psm_word interrupt_psm
reconnect_initiate_word reconnect_initiate
@@ -64,6 +68,7 @@
bdaddrstring {hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}
hexbytestring 0x{hexbyte}
+hexwordstring 0x{hexword}
%%
@@ -78,6 +83,9 @@
{device_word} return (T_DEVICE);
{bdaddr_word} return (T_BDADDR);
+{vendor_id_word} return (T_VENDOR_ID);
+{product_id_word} return (T_PRODUCT_ID);
+{version_word} return (T_VERSION);
{control_psm_word} return (T_CONTROL_PSM);
{interrupt_psm_word} return (T_INTERRUPT_PSM);
{reconnect_initiate_word} return (T_RECONNECT_INITIATE);
@@ -100,6 +108,14 @@
return (*ep == '\0'? T_HEXBYTE : T_ERROR);
}
+{hexwordstring} {
+ char *ep;
+
+ yylval.num = strtoul(yytext, &ep, 16);
+
+ return (*ep == '\0'? T_HEXWORD : T_ERROR);
+ }
+
. return (T_ERROR);
%%
Index: /usr/src/usr.sbin/bluetooth/bthidd/parser.y
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/parser.y
+++ /usr/src/usr.sbin/bluetooth/bthidd/parser.y
@@ -86,8 +86,10 @@
%token <bdaddr> T_BDADDRSTRING
%token <num> T_HEXBYTE
-%token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE
-%token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
+%token <num> T_HEXWORD
+%token T_DEVICE T_BDADDR T_VENDOR_ID T_PRODUCT_ID T_VERSION T_CONTROL_PSM
+%token T_INTERRUPT_PSM T_RECONNECT_INITIATE T_BATTERY_POWER
+%token T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
%token T_TRUE T_FALSE T_ERROR
%%
@@ -123,6 +125,9 @@
;
option: bdaddr
+ | vendor_id
+ | product_id
+ | version
| control_psm
| interrupt_psm
| reconnect_initiate
@@ -138,6 +143,24 @@
}
;
+vendor_id: T_VENDOR_ID T_HEXWORD
+ {
+ hid_device->vendor_id = $2;
+ }
+ ;
+
+product_id: T_PRODUCT_ID T_HEXWORD
+ {
+ hid_device->product_id = $2;
+ }
+ ;
+
+version: T_VERSION T_HEXWORD
+ {
+ hid_device->version = $2;
+ }
+ ;
+
control_psm: T_CONTROL_PSM T_HEXBYTE
{
hid_device->control_psm = $2;
@@ -306,6 +329,9 @@
fprintf(f,
"device {\n" \
" bdaddr %s;\n" \
+" vendor_id 0x%04x;\n" \
+" product_id 0x%04x;\n" \
+" version 0x%04x;\n" \
" control_psm 0x%x;\n" \
" interrupt_psm 0x%x;\n" \
" reconnect_initiate %s;\n" \
@@ -313,6 +339,7 @@
" normally_connectable %s;\n" \
" hid_descriptor {",
bt_ntoa(&d->bdaddr, NULL),
+ d->vendor_id, d->product_id, d->version,
d->control_psm, d->interrupt_psm,
d->reconnect_initiate? "true" : "false",
d->battery_power? "true" : "false",
Index: /usr/src/usr.sbin/bluetooth/bthidd/server.c
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/server.c
+++ /usr/src/usr.sbin/bluetooth/bthidd/server.c
@@ -286,6 +286,10 @@
srv->maxfd = s->vkbd;
}
+ /* Pass device for probing after both channels are established */
+ if (s->state == OPEN)
+ hid_initialise(s);
+
return (0);
}
Index: /usr/src/usr.sbin/bluetooth/bthidd/session.c
===================================================================
--- /usr/src/usr.sbin/bluetooth/bthidd/session.c
+++ /usr/src/usr.sbin/bluetooth/bthidd/session.c
@@ -65,6 +65,7 @@
memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
s->ctrl = -1;
s->intr = -1;
+ s->ctx = NULL;
if (d->keyboard) {
/* Open /dev/vkbdctl */
@@ -175,6 +176,7 @@
s->srv->maxfd --;
}
+ free(s->ctx);
free(s->keys1);
free(s->keys2);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 22, 5:32 PM (3 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25982530
Default Alt Text
D3702.id8902.diff (13 KB)
Attached To
Mode
D3702: Add support for vendor_id, product_id and version in bthidd. Adds support for Apple's magic mouse
Attached
Detach File
Event Timeline
Log In to Comment