2011-04-10 06:04:29 -06:00
|
|
|
/*
|
|
|
|
* Copyright © 2011 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
|
|
* and its documentation for any purpose is hereby granted without
|
|
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
|
|
* and that both that copyright notice and this permission notice
|
|
|
|
* appear in supporting documentation, and that the name of Red Hat
|
|
|
|
* not be used in advertising or publicity pertaining to distribution
|
|
|
|
* of the software without specific, written prior permission. Red
|
|
|
|
* Hat makes no representations about the suitability of this software
|
|
|
|
* for any purpose. It is provided "as is" without express or implied
|
|
|
|
* warranty.
|
|
|
|
*
|
|
|
|
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
|
|
* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Peter Hutterer
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "synaptics.h"
|
|
|
|
#include "synapticsstr.h"
|
|
|
|
#include "eventcomm.h"
|
|
|
|
|
|
|
|
#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
|
|
|
|
|
|
|
|
int fd_read, fd_write;
|
|
|
|
|
|
|
|
/* A syn event, always handy to have */
|
|
|
|
struct input_event syn = { {0, 0}, EV_SYN, SYN_REPORT, 0 };
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_pipe_fd(void)
|
|
|
|
{
|
|
|
|
int pipefd[2];
|
|
|
|
|
|
|
|
assert(pipe(pipefd) != -1);
|
|
|
|
|
|
|
|
fd_read = pipefd[0];
|
|
|
|
fd_write = pipefd[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(struct SynapticsHwState **hw, struct CommData *comm,
|
|
|
|
SynapticsPrivate * priv)
|
2011-04-10 06:04:29 -06:00
|
|
|
{
|
2012-06-12 12:59:42 -06:00
|
|
|
SynapticsHwStateFree(&comm->hwState);
|
2011-04-10 06:04:29 -06:00
|
|
|
memset(comm, 0, sizeof(struct CommData));
|
2012-06-12 12:59:42 -06:00
|
|
|
SynapticsHwStateFree(hw);
|
|
|
|
*hw = SynapticsHwStateAlloc(priv);
|
|
|
|
comm->hwState = SynapticsHwStateAlloc(priv);
|
2011-04-10 06:04:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write n input events to fd, followed by the syn event.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
write_event(int fd, struct input_event *ev, int n)
|
|
|
|
{
|
|
|
|
write(fd, ev, sizeof(struct input_event) * n);
|
|
|
|
write(fd, &syn, sizeof(syn));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-06-12 12:59:42 -06:00
|
|
|
test_buttons(int fd, InputInfoPtr pInfo, struct CommData *comm)
|
2011-04-10 06:04:29 -06:00
|
|
|
{
|
2012-06-12 12:59:42 -06:00
|
|
|
SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
|
|
|
|
struct SynapticsHwState *hw = NULL;
|
|
|
|
struct input_event ev = { {0, 0}, EV_KEY, 0, 0 };
|
2011-04-10 06:04:29 -06:00
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, comm, priv);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
#define _test_press_release(_code, field) \
|
|
|
|
ev.code = (_code); \
|
|
|
|
ev.value = 1; \
|
|
|
|
write_event(fd, &ev, 1); \
|
|
|
|
EventReadHwState(pInfo, comm, hw); \
|
|
|
|
assert(hw->field == 1); \
|
|
|
|
ev.value = 0; /* button release */ \
|
|
|
|
write_event(fd_write, &ev, 1); \
|
|
|
|
EventReadHwState(pInfo, comm, hw); \
|
|
|
|
assert(hw->field == 0);
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
_test_press_release(BTN_LEFT, left);
|
|
|
|
_test_press_release(BTN_RIGHT, right);
|
|
|
|
_test_press_release(BTN_MIDDLE, middle);
|
|
|
|
_test_press_release(BTN_FORWARD, up);
|
|
|
|
_test_press_release(BTN_BACK, down);
|
|
|
|
_test_press_release(BTN_0, multi[0]);
|
|
|
|
_test_press_release(BTN_1, multi[1]);
|
|
|
|
_test_press_release(BTN_2, multi[2]);
|
|
|
|
_test_press_release(BTN_3, multi[3]);
|
|
|
|
_test_press_release(BTN_4, multi[4]);
|
|
|
|
_test_press_release(BTN_5, multi[5]);
|
|
|
|
_test_press_release(BTN_6, multi[6]);
|
|
|
|
_test_press_release(BTN_7, multi[7]);
|
|
|
|
|
|
|
|
SynapticsHwStateFree(&hw);
|
2011-04-10 06:04:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This test checks that the recognised event fields set the right hardware
|
|
|
|
* state. It's a fairly limited test and does not check whether any of the
|
|
|
|
* others change the HW state at all.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
test_read_hw_state(void)
|
|
|
|
{
|
2012-06-12 12:59:42 -06:00
|
|
|
InputInfoRec info = { 0 };
|
|
|
|
SynapticsPrivate private;
|
|
|
|
struct SynapticsHwState *hw = NULL;
|
|
|
|
struct CommData comm = { 0 };
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
struct input_event ev[] = {
|
2012-06-12 12:59:42 -06:00
|
|
|
{{0, 0}, EV_KEY, BTN_TOOL_FINGER, 1},
|
|
|
|
{{0, 0}, EV_KEY, BTN_TOOL_DOUBLETAP, 1},
|
|
|
|
{{0, 0}, EV_KEY, BTN_TOOL_TRIPLETAP, 1},
|
|
|
|
{{0, 0}, EV_ABS, ABS_X, 42},
|
|
|
|
{{0, 0}, EV_ABS, ABS_Y, 21},
|
|
|
|
{{0, 0}, EV_ABS, ABS_PRESSURE, 56},
|
|
|
|
{{0, 0}, EV_ABS, ABS_TOOL_WIDTH, 204},
|
2011-04-10 06:04:29 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
memset(&private, 0, sizeof(private));
|
|
|
|
|
|
|
|
info.private = &private;
|
|
|
|
info.fd = fd_read;
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
private.proto_data = EventProtoDataAlloc();
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* just the syn event */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write(fd_write, &syn, sizeof(syn));
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->numFingers == 0);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* one finger */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[0], 1);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->numFingers == 1);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* two fingers */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[1], 1);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->numFingers == 2);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* three fingers */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[2], 1);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->numFingers == 3);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* x/y data */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[3], 2);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->x == ev[3].value);
|
|
|
|
assert(hw->y == ev[4].value);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* pressure */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[5], 1);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->z == ev[5].value);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* finger width */
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private);
|
2011-04-10 06:04:29 -06:00
|
|
|
write_event(fd_write, &ev[6], 1);
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw);
|
|
|
|
assert(hw->fingerWidth == ev[6].value);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
/* the various buttons */
|
2012-06-12 12:59:42 -06:00
|
|
|
test_buttons(fd_write, &info, &comm);
|
|
|
|
|
|
|
|
free(private.proto_data);
|
|
|
|
SynapticsHwStateFree(&hw);
|
|
|
|
SynapticsHwStateFree(&comm.hwState);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
compare_hw_state(const struct SynapticsHwState *a,
|
|
|
|
const struct SynapticsHwState *b)
|
|
|
|
{
|
|
|
|
#define COMPARE(x) \
|
|
|
|
if (a->x != b->x) return a->x - b->x
|
|
|
|
|
|
|
|
COMPARE(millis);
|
|
|
|
COMPARE(x);
|
|
|
|
COMPARE(y);
|
|
|
|
COMPARE(z);
|
|
|
|
COMPARE(numFingers);
|
|
|
|
COMPARE(fingerWidth);
|
|
|
|
COMPARE(left);
|
|
|
|
COMPARE(right);
|
|
|
|
COMPARE(up);
|
|
|
|
COMPARE(down);
|
|
|
|
if (memcmp(a->multi, b->multi, sizeof(a->multi)))
|
|
|
|
return memcmp(a->multi, b->multi, sizeof(a->multi));
|
|
|
|
COMPARE(middle);
|
|
|
|
|
|
|
|
#undef COMPARE
|
|
|
|
|
|
|
|
return 0;
|
2011-04-10 06:04:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make sure that axes/keys unknown to the driver don't change the hardware
|
|
|
|
* state.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
test_ignore_hw_state(void)
|
|
|
|
{
|
|
|
|
int i;
|
2012-06-12 12:59:42 -06:00
|
|
|
InputInfoRec info = { 0 };
|
|
|
|
SynapticsPrivate private;
|
|
|
|
struct SynapticsHwState *hw = NULL;
|
|
|
|
struct SynapticsHwState *hw_zero = NULL;
|
|
|
|
struct CommData comm = { 0 };
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
int known_abs[] = {
|
|
|
|
ABS_X,
|
|
|
|
ABS_Y,
|
|
|
|
ABS_PRESSURE,
|
|
|
|
ABS_TOOL_WIDTH,
|
|
|
|
};
|
|
|
|
|
|
|
|
int known_keys[] = {
|
|
|
|
BTN_LEFT,
|
|
|
|
BTN_RIGHT,
|
|
|
|
BTN_MIDDLE,
|
|
|
|
BTN_FORWARD,
|
|
|
|
BTN_BACK,
|
|
|
|
BTN_0,
|
|
|
|
BTN_1,
|
|
|
|
BTN_2,
|
|
|
|
BTN_3,
|
|
|
|
BTN_4,
|
|
|
|
BTN_5,
|
|
|
|
BTN_6,
|
|
|
|
BTN_7,
|
|
|
|
BTN_TOOL_FINGER,
|
|
|
|
BTN_TOOL_DOUBLETAP,
|
|
|
|
BTN_TOOL_TRIPLETAP,
|
|
|
|
BTN_TOUCH
|
|
|
|
};
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
struct input_event ev = { {0, 0}, 0, 0, 1 };
|
2011-04-10 06:04:29 -06:00
|
|
|
|
|
|
|
memset(&private, 0, sizeof(private));
|
|
|
|
info.private = &private;
|
|
|
|
info.fd = fd_read;
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
private.proto_data = EventProtoDataAlloc();
|
|
|
|
|
|
|
|
reset_data(&hw_zero, &comm, &private);
|
|
|
|
|
2011-04-10 06:04:29 -06:00
|
|
|
#define _assert_no_change(_type, _code) \
|
2012-06-12 12:59:42 -06:00
|
|
|
reset_data(&hw, &comm, &private); \
|
2011-04-10 06:04:29 -06:00
|
|
|
ev.type = _type; \
|
|
|
|
ev.code = _code; \
|
|
|
|
ev.value = 1; \
|
|
|
|
write_event(fd_write, &ev, 1); \
|
2012-06-12 12:59:42 -06:00
|
|
|
EventReadHwState(&info, &comm, hw); \
|
|
|
|
assert(compare_hw_state(hw, hw_zero) == 0);
|
2011-04-10 06:04:29 -06:00
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
for (i = ABS_X; i < ABS_MAX; i++) {
|
2011-04-10 06:04:29 -06:00
|
|
|
int j, skip = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < ArrayLength(known_abs); j++) {
|
|
|
|
if (i == known_abs[j]) {
|
|
|
|
skip = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (skip)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
_assert_no_change(EV_ABS, i);
|
|
|
|
}
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
for (i = KEY_RESERVED; i < KEY_MAX; i++) {
|
2011-04-10 06:04:29 -06:00
|
|
|
int j, skip = 0;
|
2012-06-12 12:59:42 -06:00
|
|
|
|
2011-04-10 06:04:29 -06:00
|
|
|
for (j = 0; j < ArrayLength(known_keys); j++) {
|
|
|
|
if (i == known_keys[j]) {
|
|
|
|
skip = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (skip)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
_assert_no_change(EV_KEY, i);
|
|
|
|
}
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
free(private.proto_data);
|
|
|
|
SynapticsHwStateFree(&hw);
|
|
|
|
SynapticsHwStateFree(&hw_zero);
|
|
|
|
SynapticsHwStateFree(&comm.hwState);
|
2011-04-10 06:04:29 -06:00
|
|
|
}
|
|
|
|
|
2012-06-12 12:59:42 -06:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2011-04-10 06:04:29 -06:00
|
|
|
{
|
|
|
|
create_pipe_fd();
|
|
|
|
|
|
|
|
test_read_hw_state();
|
|
|
|
test_ignore_hw_state();
|
|
|
|
return 0;
|
|
|
|
}
|