#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include "hid-ids.h"
#include "hid-logitech-hidpp.h"
MODULE_LICENSE("GPL");
sizeof(struct hidpp_report),
HID_OUTPUT_REPORT);
- return (sent_bytes < 0) ? sent_bytes : 0;
+ /* It seems that sending via bluetooth can return -EIO even
+ * when the message is delivered, so we have this hack: */
+ return (sent_bytes < 0 && sent_bytes != -EIO) ? sent_bytes : 0;
}
static int hidpp_send_message_sync(struct hidpp_device *hidpp_dev,
memset(&message, 0, sizeof(message));
message.report_id = report_id;
+ /* If sending to a non-DJ device, device expects 0xff. If sending to
+ * a DJ device, this device_index will be overwritten by the DJ code: */
+ message.device_index = 0xff;
message.rap.sub_id = sub_id;
message.rap.reg_address = reg_address;
memcpy(&message.rap.params, params, param_count);
params[0] = feature_id >> 8;
params[1] = feature_id & 0xff;
ret = hidpp_send_hidpp2_sync(hidpp_dev,
- REPORT_ID_HIDPP_SHORT,
+ REPORT_ID_HIDPP_LONG,
0,
0,
software_id,
hidpp_print_raw_event("hidpp_raw_event", data, size);
- if ((report->report_id != REPORT_ID_HIDPP_LONG) &&
- (report->report_id != REPORT_ID_HIDPP_SHORT)) {
+ if (!(report->report_id == REPORT_ID_HIDPP_LONG ||
+ report->report_id == REPORT_ID_HIDPP_SHORT ||
+ (report->report_id == T651_REPORT_TYPE_MOUSE &&
+ hdev->product == USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651))) {
dbg_hid("hid-logitech-hidpp.c:%s: ignore report_id:%d\n",
__func__, report->report_id);
return 0;
__u16 next_tracking_id;
__u16 current_slots_used; /* slots = device IDs. Bitmask. */
__u16 prev_slots_used; /* slots = device IDs. Bitmask. */
+
+ __u8 fingers_seen_this_frame;
};
static void wtp_touch_event(struct wtp_data *fd,
bool new_finger = !(fd->prev_slots_used & (1 << slot));
fd->current_slots_used |= 1 << slot;
+ fd->fingers_seen_this_frame++;
input_mt_slot(fd->input, slot);
if (new_finger) {
wtp_touch_event(fd, &event->fingers[i]);
}
- if (event->end_of_frame || finger_count <= 2) {
+ if (event->end_of_frame || finger_count < 2 ||
+ (finger_count == 2 && hidpp_dev->hid_dev->product ==
+ UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD)) {
+ u8 fingers_this_frame = fd->fingers_seen_this_frame;
for (i = 0; i < SLOT_COUNT; i++) {
__u16 slot_mask = 1 << i;
bool released = (fd->prev_slots_used & slot_mask) &&
}
input_mt_report_pointer_emulation(fd->input, true);
input_report_key(fd->input, BTN_TOOL_FINGER,
- finger_count == 1);
+ fingers_this_frame == 1);
input_report_key(fd->input, BTN_TOOL_DOUBLETAP,
- finger_count == 2);
+ fingers_this_frame == 2);
input_report_key(fd->input, BTN_TOOL_TRIPLETAP,
- finger_count == 3);
+ fingers_this_frame == 3);
input_report_key(fd->input, BTN_TOOL_QUADTAP,
- finger_count == 4);
+ fingers_this_frame == 4);
input_report_key(fd->input, BTN_TOOL_QUINTTAP,
- finger_count == 5);
+ fingers_this_frame == 5);
/* WTP Uses normal mouse reports for button state */
if (hidpp_dev->hid_dev->product !=
UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD)
fd->prev_slots_used = fd->current_slots_used;
fd->current_slots_used = 0;
+ fd->fingers_seen_this_frame = 0;
}
return 1;
}
/* Ensure we get the proper raw data report here. We do this after
the parsing above to avoid mixed declarations and code. */
- if (hidpp_report->report_id != REPORT_ID_HIDPP_LONG ||
+ if ((hidpp_report->report_id != REPORT_ID_HIDPP_LONG ||
hidpp_report->rap.sub_id != fd->mt_feature_index ||
- (hidpp_report->rap.reg_address >> 4) != WTP_RAW_XY_EVENT_INDEX) {
+ (hidpp_report->rap.reg_address >> 4) != WTP_RAW_XY_EVENT_INDEX) &&
+ !(hidpp_report->report_id == T651_REPORT_TYPE_MOUSE &&
+ hidpp_device->hid_dev->product == USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651)) {
dbg_hid("Unhandled event type\n");
return 0;
}
+ if (hidpp_report->report_id == T651_REPORT_TYPE_MOUSE &&
+ hidpp_device->hid_dev->product == USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651) {
+ /* Approximate area as (w^2 + h^2) / 2: */
+ u8 c1_area = ((buf[10] & 0xf) * (buf[10] & 0xf) +
+ (buf[10] >> 4) * (buf[10] >> 4)) / 2;
+ u8 c2_area = ((buf[16] & 0xf) * (buf[16] & 0xf) +
+ (buf[16] >> 4) * (buf[16] >> 4)) / 2;
+ struct hidpp_touchpad_raw_xy raw_xy_t651 = {
+ buf[4], /* Timestamp */
+ { {
+ 0, /* Contact type */
+ c1_area > 0, /* Contact status */
+ (buf[7] << 8) | buf[6], /* X */
+ (buf[9] << 8) | buf[8], /* Y */
+ c1_area, /* Z/Force */
+ c1_area, /* Area */
+ buf[5] /* Finger ID */
+ }, {
+ 0, /* Contact type */
+ c2_area > 0, /* Contact status */
+ (buf[13] << 8) | buf[12], /* X */
+ (buf[15] << 8) | buf[14], /* Y */
+ c2_area, /* Z/Force */
+ c2_area, /* Area */
+ buf[11] /* Finger ID */
+ } },
+ (buf[5] != 0) + (buf[11] != 0), /* Fingers this frame */
+ 0, /* Proximity */
+ buf[3] & 1, /* Mechanical button */
+ 0, /* Spurious flag */
+ (buf[3] >> 7) == 0 /* EOF */
+ };
+ raw_xy = raw_xy_t651;
+ }
+
dbg_hid("EVT: %d {ty: %d, st: %d, (%d,%d,%d,%d) id:%d} {ty: %d, st: %d, (%d,%d,%d,%d) id:%d} cnt:%d pr:%d but:%d sf:%d eof:%d\n",
raw_xy.timestamp,
raw_xy.fingers[0].contact_type,
remaining bits - reserved */
u8 params = 0x5;
+ if (hidpp_dev->hid_dev->product == USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651) {
+ dbg_hid("not going to raw for T651\n");
+ return 0;
+ }
+
ret = hidpp_send_fap_command_sync(hidpp_dev, fd->mt_feature_index,
CMD_TOUCHPAD_SET_RAW_REPORT_STATE, ¶ms, 1, &response);
hid_device_io_start(hdev);
/* Get hid++ version number */
- ret = hidpp_send_hidpp2_sync(hidpp_device, REPORT_ID_HIDPP_SHORT,
+ ret = hidpp_send_hidpp2_sync(hidpp_device, REPORT_ID_HIDPP_LONG,
0, 1,
SOFTWARE_ID,
NULL, 0, &response);
static const struct hid_device_id wtp_devices[] = {
{HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD) },
{HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD_T650) },
+ {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651) },
{ }
};
MODULE_DEVICE_TABLE(hid, wtp_devices);