Skip to content

Commit

Permalink
hid: egalax: Convert to MT slots
Browse files Browse the repository at this point in the history
The firmware in the joojoo reports touches sequentially, one per
report, which confuses the current driver. A further complication is
the absense of any indication of a touch frame. This patch converts
the driver to the MT slots protocol, and outputs one full touch frame
per report. This way, proper handling for both firmwares is ensured.

Tested-by: Philipp Merkel <mail@philmerk.de>
Cc: Stephane Chatty <chatty@enac.fr>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
  • Loading branch information
Henrik Rydberg committed Dec 16, 2010
1 parent 17c7606 commit f7bc804
Showing 1 changed file with 23 additions and 63 deletions.
86 changes: 23 additions & 63 deletions drivers/hid/hid-egalax.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* HID driver for eGalax dual-touch panels
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/

Expand All @@ -16,6 +18,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
#include <linux/slab.h>
#include "usbhid/usbhid.h"

Expand All @@ -25,17 +28,17 @@ MODULE_LICENSE("GPL");

#include "hid-ids.h"

#define MAX_SLOTS 2

/* estimated signal-to-noise ratios */
#define SN_MOVE 4096
#define SN_PRESSURE 32

struct egalax_data {
__u16 x, y, z;
__u8 id;
bool first; /* is this the first finger in the frame? */
bool valid; /* valid finger data, or just placeholder? */
bool activity; /* at least one active finger previously? */
__u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
int valid;
int slot;
int touch;
int x, y, z;
};

static void set_abs(struct input_dev *input, unsigned int code,
Expand Down Expand Up @@ -89,9 +92,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
set_abs(input, ABS_MT_TRACKING_ID, field, 0);
input_mt_init_slots(input, MAX_SLOTS);
return 1;
case HID_DG_TIPPRESSURE:
field->logical_minimum = 0;
Expand Down Expand Up @@ -125,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/
static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
{
td->first = !td->first; /* touchscreen emulation */

if (td->valid) {
/* emit multitouch events */
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
input_mt_slot(input, td->slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
if (td->touch) {
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);

input_mt_sync(input);

/*
* touchscreen emulation: store (x, y) as
* the last valid values in this frame
*/
td->lastx = td->x;
td->lasty = td->y;
td->lastz = td->z;
}

/*
* touchscreen emulation: if this is the second finger and at least
* one in this frame is valid, the latest valid in the frame is
* the oldest on the panel, the one we want for single touch
*/
if (!td->first && td->activity) {
input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
}

if (!td->valid) {
/*
* touchscreen emulation: if the first finger is invalid
* and there previously was finger activity, this is a release
*/
if (td->first && td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
td->activity = false;
}
return;
}


/* touchscreen emulation: if no previous activity, emit touch event */
if (!td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
td->activity = true;
}
input_mt_report_pointer_emulation(input, true);
}


static int egalax_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
Expand All @@ -186,37 +145,38 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
* uses a standard parallel multitouch protocol (product ID ==
* 48xx). The second is capacitive and uses an unusual "serial"
* protocol with a different message for each multitouch finger
* (product ID == 72xx). We do not yet generate a correct event
* sequence for the capacitive/serial protocol.
* (product ID == 72xx).
*/
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;

switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = value;
break;
case HID_DG_CONFIDENCE:
/* avoid interference from generic hidinput handling */
break;
case HID_DG_TIPSWITCH:
td->valid = value;
td->touch = value;
break;
case HID_DG_TIPPRESSURE:
td->z = value;
break;
case HID_DG_CONTACTID:
td->id = value;
td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
break;
case HID_GD_X:
td->x = value;
break;
case HID_GD_Y:
td->y = value;
/* this is the last field in a finger */
egalax_filter_event(td, input);
if (td->valid)
egalax_filter_event(td, input);
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
td->first = false;
break;

default:
Expand Down

0 comments on commit f7bc804

Please sign in to comment.