Changeset View
Standalone View
/usr/src/usr.sbin/bluetooth/bthidd/hid.c
Context not available. | |||||
#include <dev/usb/usbhid.h> | #include <dev/usb/usbhid.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include <syslog.h> | #include <syslog.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
Context not available. | |||||
#include "kbd.h" | #include "kbd.h" | ||||
/* | /* | ||||
* Inoffical and unannounced report ids for Apple Mice and trackpad | |||||
*/ | |||||
#define TRACKPAD_REPORT_ID 0x28 | |||||
#define MOUSE_REPORT_ID 0x29 | |||||
#define BATT_STAT_REPORT_ID 0x30 | |||||
#define BATT_STRENGTH_REPORT_ID 0x47 | |||||
#define SURFACE_REPORT_ID 0x61 | |||||
/* | |||||
* Magic mouse specific device state | |||||
*/ | |||||
#define MAGIC_MOUSE_MAX_BUTTONS 16 | |||||
struct apple_state { | |||||
int y [MAGIC_MOUSE_MAX_BUTTONS]; | |||||
int button_state; | |||||
}; | |||||
#define MAGIC_MOUSE(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30d)) | |||||
#define SCROLL_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(sizeof(struct apple_state), 1)) == NULL) | |||||
emax: arguments to calloc() reversed, i.e. its number then size. does not really matter though. just… | |||||
Not Done Inline ActionsYep. Fixed. erdgeist_erdgeist.org: Yep. Fixed. | |||||
return; | |||||
write(s->ctrl, rep, 3); | |||||
} | |||||
} | |||||
/* | |||||
* Process data from control channel | * Process data from control channel | ||||
*/ | */ | ||||
Context not available. | |||||
hid_end_parse(d); | 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 */ | |||||
Not Done Inline Actionswhat's up with prefix in/decrements? :) also why on one line? emax: what's up with prefix in/decrements? :) also why on one line? | |||||
Not Done Inline ActionsPrefix reads more natural: "Increase data", "Increase len." But if you insist ;) Fixed now. Single line and comma operator, because it modifies the same logical unit { uint8_t * data, size_t len } describing the buffer. Order does not matter, so language conventions say: prefer comma operator. erdgeist_erdgeist.org: Prefix reads more natural: "Increase data", "Increase len."
But if you insist ;) Fixed now. | |||||
if (report_id != MOUSE_REPORT_ID || | |||||
len < 5 || len > 5 + 8 * 15 || len % 8 != 5) | |||||
Not Done Inline Actionsmagic numbers are magical :) perhaps a comment explaining where those came from? emax: magic numbers are magical :) perhaps a comment explaining where those came from? | |||||
Not Done Inline ActionsAgain. I was afraid that apple specific code takes too much space, already in sources. Fixed. erdgeist_erdgeist.org: Again. I was afraid that apple specific code takes too much space, already in sources. Fixed. | |||||
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++; | |||||
Not Done Inline Actionssame as above. why use comma? emax: same as above. why use comma? | |||||
Not Done Inline ActionsSame logical unit: The mouse_x += operation only is valid, if mevents is set. Order does not matter, operating on the logical struct { int mouse_x, bool mevents_valid }, so comma operator is preferrable. erdgeist_erdgeist.org: Same logical unit: The mouse_x += operation only is valid, if mevents is set.
Order does not… | |||||
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 += 5, len -= 5; len >= 8; data += 8, len -= 8) { | |||||
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]) / SCROLL_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 * SCROLL_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++; | |||||
Not Done Inline Actionscomma again emax: comma again | |||||
Not Done Inline ActionsWhat do you have against comma operator? It is used as language conventions imply. erdgeist_erdgeist.org: What do you have against comma operator? It is used as language conventions imply. | |||||
} | |||||
/* | |||||
* XXX FIXME Feed keyboard events into kernel. | * XXX FIXME Feed keyboard events into kernel. | ||||
* The code below works, bit host also needs to track | * The code below works, bit host also needs to track | ||||
* and handle repeat. | * and handle repeat. | ||||
Context not available. | |||||
mi.u.data.y = mouse_y; | mi.u.data.y = mouse_y; | ||||
mi.u.data.z = mouse_z; | mi.u.data.z = mouse_z; | ||||
mi.u.data.buttons = mouse_butt; | mi.u.data.buttons = mouse_butt; | ||||
if (ioctl(s->srv->cons, CONS_MOUSECTL, &mi) < 0) | if (ioctl(s->srv->cons, CONS_MOUSECTL, &mi) < 0) | ||||
syslog(LOG_ERR, "Could not process mouse events from " \ | syslog(LOG_ERR, "Could not process mouse events from " \ | ||||
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL), | "%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL), | ||||
Context not available. |
arguments to calloc() reversed, i.e. its number then size. does not really matter though. just being pedantic