Merge branch 'for-next' of git://github.com/rydberg/linux into next

Merge Henrik's updates to multitouch code. Even though Jiri already
pulled them in I need to do it too since my changes to evdev using
dynamic major would clash with them.
This commit is contained in:
Dmitry Torokhov 2012-10-01 14:40:51 -07:00
commit 7774036808
25 changed files with 890 additions and 509 deletions

View File

@ -283,6 +283,9 @@
#define USB_VENDOR_ID_EMS 0x2006 #define USB_VENDOR_ID_EMS 0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
#define USB_VENDOR_ID_FLATFROG 0x25b5
#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100

View File

@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid)
int hidinput_connect(struct hid_device *hid, unsigned int force) int hidinput_connect(struct hid_device *hid, unsigned int force)
{ {
struct hid_driver *drv = hid->driver;
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = NULL; struct hid_input *hidinput = NULL;
struct input_dev *input_dev; struct input_dev *input_dev;
@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
* UGCI) cram a lot of unrelated inputs into the * UGCI) cram a lot of unrelated inputs into the
* same interface. */ * same interface. */
hidinput->report = report; hidinput->report = report;
if (drv->input_configured)
drv->input_configured(hid, hidinput);
if (input_register_device(hidinput->input)) if (input_register_device(hidinput->input))
goto out_cleanup; goto out_cleanup;
hidinput = NULL; hidinput = NULL;
@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
} }
} }
if (hidinput && input_register_device(hidinput->input)) if (hidinput) {
goto out_cleanup; if (drv->input_configured)
drv->input_configured(hid, hidinput);
if (input_register_device(hidinput->input))
goto out_cleanup;
}
return 0; return 0;

View File

@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
__set_bit(EV_ABS, input->evbit); __set_bit(EV_ABS, input->evbit);
error = input_mt_init_slots(input, 16); error = input_mt_init_slots(input, 16, 0);
if (error) if (error)
return error; return error;
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,

View File

@ -51,12 +51,12 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_VALID_IS_INRANGE (1 << 5) #define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
#define MT_QUIRK_NO_AREA (1 << 9)
struct mt_slot { struct mt_slot {
__s32 x, y, p, w, h; __s32 x, y, p, w, h;
__s32 contactid; /* the device ContactID assigned to this slot */ __s32 contactid; /* the device ContactID assigned to this slot */
bool touch_state; /* is the touch valid? */ bool touch_state; /* is the touch valid? */
bool seen_in_this_frame;/* has this slot been updated */
}; };
struct mt_class { struct mt_class {
@ -92,8 +92,9 @@ struct mt_device {
__u8 touches_by_report; /* how many touches are present in one report: __u8 touches_by_report; /* how many touches are present in one report:
* 1 means we should use a serial protocol * 1 means we should use a serial protocol
* > 1 means hybrid (multitouch) protocol */ * > 1 means hybrid (multitouch) protocol */
bool serial_maybe; /* need to check for serial protocol */
bool curvalid; /* is the current contact valid? */ bool curvalid; /* is the current contact valid? */
struct mt_slot *slots; unsigned mt_flags; /* flags to pass to input-mt */
}; };
/* classes of device behavior */ /* classes of device behavior */
@ -115,6 +116,7 @@ struct mt_device {
#define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_EGALAX_SERIAL 0x0104
#define MT_CLS_TOPSEED 0x0105 #define MT_CLS_TOPSEED 0x0105
#define MT_CLS_PANASONIC 0x0106 #define MT_CLS_PANASONIC 0x0106
#define MT_CLS_FLATFROG 0x0107
#define MT_DEFAULT_MAXCONTACT 10 #define MT_DEFAULT_MAXCONTACT 10
@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td)
return -1; return -1;
} }
static int find_slot_from_contactid(struct mt_device *td)
{
int i;
for (i = 0; i < td->maxcontacts; ++i) {
if (td->slots[i].contactid == td->curdata.contactid &&
td->slots[i].touch_state)
return i;
}
for (i = 0; i < td->maxcontacts; ++i) {
if (!td->slots[i].seen_in_this_frame &&
!td->slots[i].touch_state)
return i;
}
/* should not occurs. If this happens that means
* that the device sent more touches that it says
* in the report descriptor. It is ignored then. */
return -1;
}
static struct mt_class mt_classes[] = { static struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT, { .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = {
MT_QUIRK_SLOT_IS_CONTACTID, MT_QUIRK_SLOT_IS_CONTACTID,
.sn_move = 2048, .sn_move = 2048,
.sn_width = 128, .sn_width = 128,
.sn_height = 128 }, .sn_height = 128,
.maxcontacts = 60,
},
{ .name = MT_CLS_CYPRESS, { .name = MT_CLS_CYPRESS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_CYPRESS, MT_QUIRK_CYPRESS,
@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = {
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
.maxcontacts = 4 }, .maxcontacts = 4 },
{ .name = MT_CLS_FLATFROG,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_NO_AREA,
.sn_move = 2048,
.maxcontacts = 40,
},
{ } { }
}; };
@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* We need to ignore fields that belong to other collections * We need to ignore fields that belong to other collections
* such as Mouse that might have the same GenericDesktop usages. */ * such as Mouse that might have the same GenericDesktop usages. */
if (field->application == HID_DG_TOUCHSCREEN) if (field->application == HID_DG_TOUCHSCREEN)
set_bit(INPUT_PROP_DIRECT, hi->input->propbit); td->mt_flags |= INPUT_MT_DIRECT;
else if (field->application != HID_DG_TOUCHPAD) else if (field->application != HID_DG_TOUCHPAD)
return 0; return 0;
/* In case of an indirect device (touchpad), we need to add /*
* specific BTN_TOOL_* to be handled by the synaptics xorg * Model touchscreens providing buttons as touchpads.
* driver.
* We also consider that touchscreens providing buttons are touchpads.
*/ */
if (field->application == HID_DG_TOUCHPAD || if (field->application == HID_DG_TOUCHPAD ||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
cls->is_indirect) { td->mt_flags |= INPUT_MT_POINTER;
set_bit(INPUT_PROP_POINTER, hi->input->propbit);
set_bit(BTN_TOOL_FINGER, hi->input->keybit);
set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit);
set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit);
set_bit(BTN_TOOL_QUADTAP, hi->input->keybit);
}
/* eGalax devices provide a Digitizer.Stylus input which overrides /* eGalax devices provide a Digitizer.Stylus input which overrides
* the correct Digitizers.Finger X/Y ranges. * the correct Digitizers.Finger X/Y ranges.
@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_POSITION_X); EV_ABS, ABS_MT_POSITION_X);
set_abs(hi->input, ABS_MT_POSITION_X, field, set_abs(hi->input, ABS_MT_POSITION_X, field,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_POSITION_Y); EV_ABS, ABS_MT_POSITION_Y);
set_abs(hi->input, ABS_MT_POSITION_Y, field, set_abs(hi->input, ABS_MT_POSITION_Y, field,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
input_mt_init_slots(hi->input, td->maxcontacts);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
td->touches_by_report++; td->touches_by_report++;
@ -398,18 +374,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_WIDTH: case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR); EV_ABS, ABS_MT_TOUCH_MAJOR);
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, if (!(cls->quirks & MT_QUIRK_NO_AREA))
cls->sn_width); set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_HEIGHT: case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR); EV_ABS, ABS_MT_TOUCH_MINOR);
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
cls->sn_height); set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
input_set_abs_params(hi->input, cls->sn_height);
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0); ABS_MT_ORIENTATION, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_PRESSURE); EV_ABS, ABS_MT_PRESSURE);
set_abs(hi->input, ABS_MT_PRESSURE, field, set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure); cls->sn_pressure);
/* touchscreen emulation */
set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
return -1; return -1;
} }
static int mt_compute_slot(struct mt_device *td) static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
{ {
__s32 quirks = td->mtclass.quirks; __s32 quirks = td->mtclass.quirks;
@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td)
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
return td->curdata.contactid - 1; return td->curdata.contactid - 1;
return find_slot_from_contactid(td); return input_mt_get_slot_by_key(input, td->curdata.contactid);
} }
/* /*
* this function is called when a whole contact has been processed, * this function is called when a whole contact has been processed,
* so that it can assign it to a slot and store the data there * so that it can assign it to a slot and store the data there
*/ */
static void mt_complete_slot(struct mt_device *td) static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
{ {
td->curdata.seen_in_this_frame = true;
if (td->curvalid) { if (td->curvalid) {
int slotnum = mt_compute_slot(td); int slotnum = mt_compute_slot(td, input);
struct mt_slot *s = &td->curdata;
if (slotnum >= 0 && slotnum < td->maxcontacts) if (slotnum < 0 || slotnum >= td->maxcontacts)
td->slots[slotnum] = td->curdata; return;
}
td->num_received++;
}
input_mt_slot(input, slotnum);
/*
* this function is called when a whole packet has been received and processed,
* so that it can decide what to send to the input layer.
*/
static void mt_emit_event(struct mt_device *td, struct input_dev *input)
{
int i;
for (i = 0; i < td->maxcontacts; ++i) {
struct mt_slot *s = &(td->slots[i]);
if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
!s->seen_in_this_frame) {
s->touch_state = false;
}
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, input_mt_report_slot_state(input, MT_TOOL_FINGER,
s->touch_state); s->touch_state);
if (s->touch_state) { if (s->touch_state) {
@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
} }
s->seen_in_this_frame = false;
} }
input_mt_report_pointer_emulation(input, true); td->num_received++;
}
/*
* this function is called when a whole packet has been received and processed,
* so that it can decide what to send to the input layer.
*/
static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
{
input_mt_sync_frame(input);
input_sync(input); input_sync(input);
td->num_received = 0; td->num_received = 0;
} }
static int mt_event(struct hid_device *hid, struct hid_field *field, static int mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) struct hid_usage *usage, __s32 value)
{ {
struct mt_device *td = hid_get_drvdata(hid); struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass.quirks; __s32 quirks = td->mtclass.quirks;
if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
if (quirks & MT_QUIRK_ALWAYS_VALID) if (quirks & MT_QUIRK_ALWAYS_VALID)
@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
} }
if (usage->hid == td->last_slot_field) if (usage->hid == td->last_slot_field)
mt_complete_slot(td); mt_complete_slot(td, field->hidinput->input);
if (field->index == td->last_field_index if (field->index == td->last_field_index
&& td->num_received >= td->num_expected) && td->num_received >= td->num_expected)
mt_emit_event(td, field->hidinput->input); mt_sync_frame(td, field->hidinput->input);
} }
@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td)
} }
} }
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
struct input_dev *input = hi->input;
/* Only initialize slots for MT input devices */
if (!test_bit(ABS_MT_POSITION_X, input->absbit))
return;
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
mt_post_parse(td);
if (td->serial_maybe)
mt_post_parse_default_settings(td);
if (cls->is_indirect)
td->mt_flags |= INPUT_MT_POINTER;
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->mt_flags |= INPUT_MT_DROP_UNUSED;
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
td->mt_flags = 0;
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret, i; int ret, i;
@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto fail; goto fail;
} }
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true;
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret) if (ret)
goto fail; goto fail;
mt_post_parse(td);
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
mt_post_parse_default_settings(td);
td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
GFP_KERNEL);
if (!td->slots) {
dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
hid_hw_stop(hdev);
ret = -ENOMEM;
goto fail;
}
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
mt_set_maxcontacts(hdev); mt_set_maxcontacts(hdev);
@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev)
struct mt_device *td = hid_get_drvdata(hdev); struct mt_device *td = hid_get_drvdata(hdev);
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
hid_hw_stop(hdev); hid_hw_stop(hdev);
kfree(td->slots);
kfree(td); kfree(td);
hid_set_drvdata(hdev, NULL); hid_set_drvdata(hdev, NULL);
} }
@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_ELO, MT_USB_DEVICE(USB_VENDOR_ID_ELO,
USB_DEVICE_ID_ELO_TS2515) }, USB_DEVICE_ID_ELO_TS2515) },
/* Flatfrog Panels */
{ .driver_data = MT_CLS_FLATFROG,
MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
USB_DEVICE_ID_MULTITOUCH_3200) },
/* GeneralTouch panel */ /* GeneralTouch panel */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = {
.remove = mt_remove, .remove = mt_remove,
.input_mapping = mt_input_mapping, .input_mapping = mt_input_mapping,
.input_mapped = mt_input_mapped, .input_mapped = mt_input_mapped,
.input_configured = mt_input_configured,
.feature_mapping = mt_feature_mapping, .feature_mapping = mt_feature_mapping,
.usage_table = mt_grabbed_usages, .usage_table = mt_grabbed_usages,
.event = mt_event, .event = mt_event,

View File

@ -54,16 +54,9 @@ struct evdev_client {
static struct evdev *evdev_table[EVDEV_MINORS]; static struct evdev *evdev_table[EVDEV_MINORS];
static DEFINE_MUTEX(evdev_table_mutex); static DEFINE_MUTEX(evdev_table_mutex);
static void evdev_pass_event(struct evdev_client *client, static void __pass_event(struct evdev_client *client,
struct input_event *event, const struct input_event *event)
ktime_t mono, ktime_t real)
{ {
event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event; client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1; client->head &= client->bufsize - 1;
@ -86,8 +79,63 @@ static void evdev_pass_event(struct evdev_client *client,
client->packet_head = client->head; client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN); kill_fasync(&client->fasync, SIGIO, POLL_IN);
} }
}
static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t mono, ktime_t real)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;
event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
for (v = vals; v != vals + count; v++) {
event.type = v->type;
event.code = v->code;
event.value = v->value;
__pass_event(client, &event);
if (v->type == EV_SYN && v->code == SYN_REPORT)
wakeup = true;
}
spin_unlock(&client->buffer_lock); spin_unlock(&client->buffer_lock);
if (wakeup)
wake_up_interruptible(&evdev->wait);
}
/*
* Pass incoming events to all connected clients.
*/
static void evdev_events(struct input_handle *handle,
const struct input_value *vals, unsigned int count)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
ktime_t time_mono, time_real;
time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_values(client, vals, count, time_mono, time_real);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_values(client, vals, count,
time_mono, time_real);
rcu_read_unlock();
} }
/* /*
@ -96,32 +144,9 @@ static void evdev_pass_event(struct evdev_client *client,
static void evdev_event(struct input_handle *handle, static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
struct evdev *evdev = handle->private; struct input_value vals[] = { { type, code, value } };
struct evdev_client *client;
struct input_event event;
ktime_t time_mono, time_real;
time_mono = ktime_get(); evdev_events(handle, vals, 1);
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event, time_mono, time_real);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event, time_mono, time_real);
rcu_read_unlock();
if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev->wait);
} }
static int evdev_fasync(int fd, struct file *file, int on) static int evdev_fasync(int fd, struct file *file, int on)
@ -653,20 +678,22 @@ static int evdev_handle_mt_request(struct input_dev *dev,
unsigned int size, unsigned int size,
int __user *ip) int __user *ip)
{ {
const struct input_mt_slot *mt = dev->mt; const struct input_mt *mt = dev->mt;
unsigned int code; unsigned int code;
int max_slots; int max_slots;
int i; int i;
if (get_user(code, &ip[0])) if (get_user(code, &ip[0]))
return -EFAULT; return -EFAULT;
if (!input_is_mt_value(code)) if (!mt || !input_is_mt_value(code))
return -EINVAL; return -EINVAL;
max_slots = (size - sizeof(__u32)) / sizeof(__s32); max_slots = (size - sizeof(__u32)) / sizeof(__s32);
for (i = 0; i < dev->mtsize && i < max_slots; i++) for (i = 0; i < mt->num_slots && i < max_slots; i++) {
if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) int value = input_mt_get_value(&mt->slots[i], code);
if (put_user(value, &ip[1 + i]))
return -EFAULT; return -EFAULT;
}
return 0; return 0;
} }
@ -1048,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = { static struct input_handler evdev_handler = {
.event = evdev_event, .event = evdev_event,
.events = evdev_events,
.connect = evdev_connect, .connect = evdev_connect,
.disconnect = evdev_disconnect, .disconnect = evdev_disconnect,
.fops = &evdev_fops, .fops = &evdev_fops,

View File

@ -14,6 +14,14 @@
#define TRKID_SGN ((TRKID_MAX + 1) >> 1) #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
{
if (dev->absinfo && test_bit(src, dev->absbit)) {
dev->absinfo[dst] = dev->absinfo[src];
dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
}
}
/** /**
* input_mt_init_slots() - initialize MT input slots * input_mt_init_slots() - initialize MT input slots
* @dev: input device supporting MT events and finger tracking * @dev: input device supporting MT events and finger tracking
@ -25,29 +33,63 @@
* May be called repeatedly. Returns -EINVAL if attempting to * May be called repeatedly. Returns -EINVAL if attempting to
* reinitialize with a different number of slots. * reinitialize with a different number of slots.
*/ */
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots) int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags)
{ {
struct input_mt *mt = dev->mt;
int i; int i;
if (!num_slots) if (!num_slots)
return 0; return 0;
if (dev->mt) if (mt)
return dev->mtsize != num_slots ? -EINVAL : 0; return mt->num_slots != num_slots ? -EINVAL : 0;
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
if (!dev->mt) if (!mt)
return -ENOMEM; goto err_mem;
dev->mtsize = num_slots; mt->num_slots = num_slots;
mt->flags = flags;
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
input_set_events_per_packet(dev, 6 * num_slots);
if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
}
if (flags & INPUT_MT_POINTER) {
__set_bit(BTN_TOOL_FINGER, dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
if (num_slots >= 3)
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
if (num_slots >= 4)
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
if (num_slots >= 5)
__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
__set_bit(INPUT_PROP_POINTER, dev->propbit);
}
if (flags & INPUT_MT_DIRECT)
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
if (flags & INPUT_MT_TRACK) {
unsigned int n2 = num_slots * num_slots;
mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
if (!mt->red)
goto err_mem;
}
/* Mark slots as 'unused' */ /* Mark slots as 'unused' */
for (i = 0; i < num_slots; i++) for (i = 0; i < num_slots; i++)
input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1); input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
dev->mt = mt;
return 0; return 0;
err_mem:
kfree(mt);
return -ENOMEM;
} }
EXPORT_SYMBOL(input_mt_init_slots); EXPORT_SYMBOL(input_mt_init_slots);
@ -60,11 +102,11 @@ EXPORT_SYMBOL(input_mt_init_slots);
*/ */
void input_mt_destroy_slots(struct input_dev *dev) void input_mt_destroy_slots(struct input_dev *dev)
{ {
kfree(dev->mt); if (dev->mt) {
kfree(dev->mt->red);
kfree(dev->mt);
}
dev->mt = NULL; dev->mt = NULL;
dev->mtsize = 0;
dev->slot = 0;
dev->trkid = 0;
} }
EXPORT_SYMBOL(input_mt_destroy_slots); EXPORT_SYMBOL(input_mt_destroy_slots);
@ -83,18 +125,24 @@ EXPORT_SYMBOL(input_mt_destroy_slots);
void input_mt_report_slot_state(struct input_dev *dev, void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active) unsigned int tool_type, bool active)
{ {
struct input_mt_slot *mt; struct input_mt *mt = dev->mt;
struct input_mt_slot *slot;
int id; int id;
if (!dev->mt || !active) { if (!mt)
return;
slot = &mt->slots[mt->slot];
slot->frame = mt->frame;
if (!active) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
return; return;
} }
mt = &dev->mt[dev->slot]; id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type) id = input_mt_new_trkid(mt);
id = input_mt_new_trkid(dev);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
@ -135,13 +183,19 @@ EXPORT_SYMBOL(input_mt_report_finger_count);
*/ */
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
{ {
struct input_mt_slot *oldest = NULL; struct input_mt *mt = dev->mt;
int oldid = dev->trkid; struct input_mt_slot *oldest;
int count = 0; int oldid, count, i;
int i;
for (i = 0; i < dev->mtsize; ++i) { if (!mt)
struct input_mt_slot *ps = &dev->mt[i]; return;
oldest = 0;
oldid = mt->trkid;
count = 0;
for (i = 0; i < mt->num_slots; ++i) {
struct input_mt_slot *ps = &mt->slots[i];
int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
if (id < 0) if (id < 0)
@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
if (oldest) { if (oldest) {
int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y); int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
input_event(dev, EV_ABS, ABS_X, x); input_event(dev, EV_ABS, ABS_X, x);
input_event(dev, EV_ABS, ABS_Y, y); input_event(dev, EV_ABS, ABS_Y, y);
input_event(dev, EV_ABS, ABS_PRESSURE, p);
if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
input_event(dev, EV_ABS, ABS_PRESSURE, p);
}
} else { } else {
input_event(dev, EV_ABS, ABS_PRESSURE, 0); if (test_bit(ABS_MT_PRESSURE, dev->absbit))
input_event(dev, EV_ABS, ABS_PRESSURE, 0);
} }
} }
EXPORT_SYMBOL(input_mt_report_pointer_emulation); EXPORT_SYMBOL(input_mt_report_pointer_emulation);
/**
* input_mt_sync_frame() - synchronize mt frame
* @dev: input device with allocated MT slots
*
* Close the frame and prepare the internal state for a new one.
* Depending on the flags, marks unused slots as inactive and performs
* pointer emulation.
*/
void input_mt_sync_frame(struct input_dev *dev)
{
struct input_mt *mt = dev->mt;
struct input_mt_slot *s;
if (!mt)
return;
if (mt->flags & INPUT_MT_DROP_UNUSED) {
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (s->frame == mt->frame)
continue;
input_mt_slot(dev, s - mt->slots);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
}
input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER));
mt->frame++;
}
EXPORT_SYMBOL(input_mt_sync_frame);
static int adjust_dual(int *begin, int step, int *end, int eq)
{
int f, *p, s, c;
if (begin == end)
return 0;
f = *begin;
p = begin + step;
s = p == end ? f + 1 : *p;
for (; p != end; p += step)
if (*p < f)
s = f, f = *p;
else if (*p < s)
s = *p;
c = (f + s + 1) / 2;
if (c == 0 || (c > 0 && !eq))
return 0;
if (s < 0)
c *= 2;
for (p = begin; p != end; p += step)
*p -= c;
return (c < s && s <= 0) || (f >= 0 && f < c);
}
static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
{
int i, k, sum;
for (k = 0; k < nrc; k++) {
for (i = 0; i < nr; i++)
adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
sum = 0;
for (i = 0; i < nrc; i += nr)
sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
if (!sum)
break;
}
}
static int input_mt_set_matrix(struct input_mt *mt,
const struct input_mt_pos *pos, int num_pos)
{
const struct input_mt_pos *p;
struct input_mt_slot *s;
int *w = mt->red;
int x, y;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (!input_mt_is_active(s))
continue;
x = input_mt_get_value(s, ABS_MT_POSITION_X);
y = input_mt_get_value(s, ABS_MT_POSITION_Y);
for (p = pos; p != pos + num_pos; p++) {
int dx = x - p->x, dy = y - p->y;
*w++ = dx * dx + dy * dy;
}
}
return w - mt->red;
}
static void input_mt_set_slots(struct input_mt *mt,
int *slots, int num_pos)
{
struct input_mt_slot *s;
int *w = mt->red, *p;
for (p = slots; p != slots + num_pos; p++)
*p = -1;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (!input_mt_is_active(s))
continue;
for (p = slots; p != slots + num_pos; p++)
if (*w++ < 0)
*p = s - mt->slots;
}
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (input_mt_is_active(s))
continue;
for (p = slots; p != slots + num_pos; p++)
if (*p < 0) {
*p = s - mt->slots;
break;
}
}
}
/**
* input_mt_assign_slots() - perform a best-match assignment
* @dev: input device with allocated MT slots
* @slots: the slot assignment to be filled
* @pos: the position array to match
* @num_pos: number of positions
*
* Performs a best match against the current contacts and returns
* the slot assignment list. New contacts are assigned to unused
* slots.
*
* Returns zero on success, or negative error in case of failure.
*/
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos)
{
struct input_mt *mt = dev->mt;
int nrc;
if (!mt || !mt->red)
return -ENXIO;
if (num_pos > mt->num_slots)
return -EINVAL;
if (num_pos < 1)
return 0;
nrc = input_mt_set_matrix(mt, pos, num_pos);
find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
input_mt_set_slots(mt, slots, num_pos);
return 0;
}
EXPORT_SYMBOL(input_mt_assign_slots);
/**
* input_mt_get_slot_by_key() - return slot matching key
* @dev: input device with allocated MT slots
* @key: the key of the sought slot
*
* Returns the slot of the given key, if it exists, otherwise
* set the key on the first unused slot and return.
*
* If no available slot can be found, -1 is returned.
*/
int input_mt_get_slot_by_key(struct input_dev *dev, int key)
{
struct input_mt *mt = dev->mt;
struct input_mt_slot *s;
if (!mt)
return -1;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
if (input_mt_is_active(s) && s->key == key)
return s - mt->slots;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
if (!input_mt_is_active(s)) {
s->key = key;
return s - mt->slots;
}
return -1;
}
EXPORT_SYMBOL(input_mt_get_slot_by_key);

View File

@ -47,6 +47,8 @@ static DEFINE_MUTEX(input_mutex);
static struct input_handler *input_table[8]; static struct input_handler *input_table[8];
static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
static inline int is_event_supported(unsigned int code, static inline int is_event_supported(unsigned int code,
unsigned long *bm, unsigned int max) unsigned long *bm, unsigned int max)
{ {
@ -69,79 +71,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
return value; return value;
} }
/*
* Pass event first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
else {
bool filtered = false;
list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (!handle->open)
continue;
handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;
handler->event(handle, type, code, value);
} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
/*
* Generate software autorepeat event. Note that we take
* dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck".
*/
static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
if (dev->sync) {
/*
* Only send SYN_REPORT if we are not in a middle
* of driver parsing a new hardware packet.
* Otherwise assume that the driver will send
* SYN_REPORT once it's done.
*/
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
static void input_start_autorepeat(struct input_dev *dev, int code) static void input_start_autorepeat(struct input_dev *dev, int code)
{ {
if (test_bit(EV_REP, dev->evbit) && if (test_bit(EV_REP, dev->evbit) &&
@ -158,14 +87,128 @@ static void input_stop_autorepeat(struct input_dev *dev)
del_timer(&dev->timer); del_timer(&dev->timer);
} }
/*
* Pass event first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static unsigned int input_to_handler(struct input_handle *handle,
struct input_value *vals, unsigned int count)
{
struct input_handler *handler = handle->handler;
struct input_value *end = vals;
struct input_value *v;
for (v = vals; v != vals + count; v++) {
if (handler->filter &&
handler->filter(handle, v->type, v->code, v->value))
continue;
if (end != v)
*end = *v;
end++;
}
count = end - vals;
if (!count)
return 0;
if (handler->events)
handler->events(handle, vals, count);
else if (handler->event)
for (v = vals; v != end; v++)
handler->event(handle, v->type, v->code, v->value);
return count;
}
/*
* Pass values first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_values(struct input_dev *dev,
struct input_value *vals, unsigned int count)
{
struct input_handle *handle;
struct input_value *v;
if (!count)
return;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle) {
count = input_to_handler(handle, vals, count);
} else {
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
count = input_to_handler(handle, vals, count);
}
rcu_read_unlock();
add_input_randomness(vals->type, vals->code, vals->value);
/* trigger auto repeat for key events */
for (v = vals; v != vals + count; v++) {
if (v->type == EV_KEY && v->value != 2) {
if (v->value)
input_start_autorepeat(dev, v->code);
else
input_stop_autorepeat(dev);
}
}
}
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };
input_pass_values(dev, vals, ARRAY_SIZE(vals));
}
/*
* Generate software autorepeat event. Note that we take
* dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck".
*/
static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
struct input_value vals[] = {
{ EV_KEY, dev->repeat_key, 2 },
input_value_sync
};
input_pass_values(dev, vals, ARRAY_SIZE(vals));
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
#define INPUT_IGNORE_EVENT 0 #define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1 #define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2 #define INPUT_PASS_TO_DEVICE 2
#define INPUT_SLOT 4
#define INPUT_FLUSH 8
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
static int input_handle_abs_event(struct input_dev *dev, static int input_handle_abs_event(struct input_dev *dev,
unsigned int code, int *pval) unsigned int code, int *pval)
{ {
struct input_mt *mt = dev->mt;
bool is_mt_event; bool is_mt_event;
int *pold; int *pold;
@ -174,8 +217,8 @@ static int input_handle_abs_event(struct input_dev *dev,
* "Stage" the event; we'll flush it later, when we * "Stage" the event; we'll flush it later, when we
* get actual touch data. * get actual touch data.
*/ */
if (*pval >= 0 && *pval < dev->mtsize) if (mt && *pval >= 0 && *pval < mt->num_slots)
dev->slot = *pval; mt->slot = *pval;
return INPUT_IGNORE_EVENT; return INPUT_IGNORE_EVENT;
} }
@ -184,9 +227,8 @@ static int input_handle_abs_event(struct input_dev *dev,
if (!is_mt_event) { if (!is_mt_event) {
pold = &dev->absinfo[code].value; pold = &dev->absinfo[code].value;
} else if (dev->mt) { } else if (mt) {
struct input_mt_slot *mtslot = &dev->mt[dev->slot]; pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
pold = &mtslot->abs[code - ABS_MT_FIRST];
} else { } else {
/* /*
* Bypass filtering for multi-touch events when * Bypass filtering for multi-touch events when
@ -205,16 +247,16 @@ static int input_handle_abs_event(struct input_dev *dev,
} }
/* Flush pending "slot" event */ /* Flush pending "slot" event */
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot); input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
} }
return INPUT_PASS_TO_HANDLERS; return INPUT_PASS_TO_HANDLERS;
} }
static void input_handle_event(struct input_dev *dev, static int input_get_disposition(struct input_dev *dev,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
int disposition = INPUT_IGNORE_EVENT; int disposition = INPUT_IGNORE_EVENT;
@ -227,37 +269,34 @@ static void input_handle_event(struct input_dev *dev,
break; break;
case SYN_REPORT: case SYN_REPORT:
if (!dev->sync) { disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
dev->sync = true;
disposition = INPUT_PASS_TO_HANDLERS;
}
break; break;
case SYN_MT_REPORT: case SYN_MT_REPORT:
dev->sync = false;
disposition = INPUT_PASS_TO_HANDLERS; disposition = INPUT_PASS_TO_HANDLERS;
break; break;
} }
break; break;
case EV_KEY: case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) && if (is_event_supported(code, dev->keybit, KEY_MAX)) {
!!test_bit(code, dev->key) != value) {
if (value != 2) { /* auto-repeat bypasses state updates */
__change_bit(code, dev->key); if (value == 2) {
if (value) disposition = INPUT_PASS_TO_HANDLERS;
input_start_autorepeat(dev, code); break;
else
input_stop_autorepeat(dev);
} }
disposition = INPUT_PASS_TO_HANDLERS; if (!!test_bit(code, dev->key) != !!value) {
__change_bit(code, dev->key);
disposition = INPUT_PASS_TO_HANDLERS;
}
} }
break; break;
case EV_SW: case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) && if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) { !!test_bit(code, dev->sw) != !!value) {
__change_bit(code, dev->sw); __change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS; disposition = INPUT_PASS_TO_HANDLERS;
@ -284,7 +323,7 @@ static void input_handle_event(struct input_dev *dev,
case EV_LED: case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) && if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) { !!test_bit(code, dev->led) != !!value) {
__change_bit(code, dev->led); __change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL; disposition = INPUT_PASS_TO_ALL;
@ -317,14 +356,48 @@ static void input_handle_event(struct input_dev *dev,
break; break;
} }
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) return disposition;
dev->sync = false; }
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition;
disposition = input_get_disposition(dev, type, code, value);
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value); dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS) if (!dev->vals)
input_pass_event(dev, type, code, value); return;
if (disposition & INPUT_PASS_TO_HANDLERS) {
struct input_value *v;
if (disposition & INPUT_SLOT) {
v = &dev->vals[dev->num_vals++];
v->type = EV_ABS;
v->code = ABS_MT_SLOT;
v->value = dev->mt->slot;
}
v = &dev->vals[dev->num_vals++];
v->type = type;
v->code = code;
v->value = value;
}
if (disposition & INPUT_FLUSH) {
if (dev->num_vals >= 2)
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
} else if (dev->num_vals >= dev->max_vals - 2) {
dev->vals[dev->num_vals++] = input_value_sync;
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
}
} }
/** /**
@ -352,7 +425,6 @@ void input_event(struct input_dev *dev,
if (is_event_supported(type, dev->evbit, EV_MAX)) { if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);
input_handle_event(dev, type, code, value); input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
} }
@ -831,10 +903,12 @@ int input_set_keycode(struct input_dev *dev,
if (test_bit(EV_KEY, dev->evbit) && if (test_bit(EV_KEY, dev->evbit) &&
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) && !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) { __test_and_clear_bit(old_keycode, dev->key)) {
struct input_value vals[] = {
{ EV_KEY, old_keycode, 0 },
input_value_sync
};
input_pass_event(dev, EV_KEY, old_keycode, 0); input_pass_values(dev, vals, ARRAY_SIZE(vals));
if (dev->sync)
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
} }
out: out:
@ -1425,6 +1499,7 @@ static void input_dev_release(struct device *device)
input_ff_destroy(dev); input_ff_destroy(dev);
input_mt_destroy_slots(dev); input_mt_destroy_slots(dev);
kfree(dev->absinfo); kfree(dev->absinfo);
kfree(dev->vals);
kfree(dev); kfree(dev);
module_put(THIS_MODULE); module_put(THIS_MODULE);
@ -1760,8 +1835,8 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
int i; int i;
unsigned int events; unsigned int events;
if (dev->mtsize) { if (dev->mt) {
mt_slots = dev->mtsize; mt_slots = dev->mt->num_slots;
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
@ -1787,6 +1862,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
if (test_bit(i, dev->relbit)) if (test_bit(i, dev->relbit))
events++; events++;
/* Make room for KEY and MSC events */
events += 7;
return events; return events;
} }
@ -1825,6 +1903,7 @@ int input_register_device(struct input_dev *dev)
{ {
static atomic_t input_no = ATOMIC_INIT(0); static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler; struct input_handler *handler;
unsigned int packet_size;
const char *path; const char *path;
int error; int error;
@ -1837,9 +1916,14 @@ int input_register_device(struct input_dev *dev)
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */ /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev); input_cleanse_bitmasks(dev);
if (!dev->hint_events_per_packet) packet_size = input_estimate_events_per_packet(dev);
dev->hint_events_per_packet = if (dev->hint_events_per_packet < packet_size)
input_estimate_events_per_packet(dev); dev->hint_events_per_packet = packet_size;
dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
if (!dev->vals)
return -ENOMEM;
/* /*
* If delay and period are pre-set by the driver, then autorepeating * If delay and period are pre-set by the driver, then autorepeating

View File

@ -416,7 +416,7 @@ static int uinput_setup_device(struct uinput_device *udev,
goto exit; goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) { if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_init_slots(dev, nslot); input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60); input_set_events_per_packet(dev, 60);
} }

View File

@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse)
case ALPS_PROTO_V3: case ALPS_PROTO_V3:
case ALPS_PROTO_V4: case ALPS_PROTO_V4:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2); input_mt_init_slots(dev1, 2, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);

View File

@ -40,6 +40,7 @@
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/input/mt.h>
#define USB_VENDOR_ID_APPLE 0x05ac #define USB_VENDOR_ID_APPLE 0x05ac
@ -183,26 +184,26 @@ struct tp_finger {
__le16 abs_y; /* absolute y coodinate */ __le16 abs_y; /* absolute y coodinate */
__le16 rel_x; /* relative x coodinate */ __le16 rel_x; /* relative x coodinate */
__le16 rel_y; /* relative y coodinate */ __le16 rel_y; /* relative y coodinate */
__le16 size_major; /* finger size, major axis? */ __le16 tool_major; /* tool area, major axis */
__le16 size_minor; /* finger size, minor axis? */ __le16 tool_minor; /* tool area, minor axis */
__le16 orientation; /* 16384 when point, else 15 bit angle */ __le16 orientation; /* 16384 when point, else 15 bit angle */
__le16 force_major; /* trackpad force, major axis? */ __le16 touch_major; /* touch area, major axis */
__le16 force_minor; /* trackpad force, minor axis? */ __le16 touch_minor; /* touch area, minor axis */
__le16 unused[3]; /* zeros */ __le16 unused[3]; /* zeros */
__le16 multi; /* one finger: varies, more fingers: constant */ __le16 multi; /* one finger: varies, more fingers: constant */
} __attribute__((packed,aligned(2))); } __attribute__((packed,aligned(2)));
/* trackpad finger data size, empirically at least ten fingers */ /* trackpad finger data size, empirically at least ten fingers */
#define MAX_FINGERS 16
#define SIZEOF_FINGER sizeof(struct tp_finger) #define SIZEOF_FINGER sizeof(struct tp_finger)
#define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER) #define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER)
#define MAX_FINGER_ORIENTATION 16384 #define MAX_FINGER_ORIENTATION 16384
/* device-specific parameters */ /* device-specific parameters */
struct bcm5974_param { struct bcm5974_param {
int dim; /* logical dimension */ int snratio; /* signal-to-noise ratio */
int fuzz; /* logical noise value */ int min; /* device minimum reading */
int devmin; /* device minimum reading */ int max; /* device maximum reading */
int devmax; /* device maximum reading */
}; };
/* device-specific configuration */ /* device-specific configuration */
@ -219,6 +220,7 @@ struct bcm5974_config {
struct bcm5974_param w; /* finger width limits */ struct bcm5974_param w; /* finger width limits */
struct bcm5974_param x; /* horizontal limits */ struct bcm5974_param x; /* horizontal limits */
struct bcm5974_param y; /* vertical limits */ struct bcm5974_param y; /* vertical limits */
struct bcm5974_param o; /* orientation limits */
}; };
/* logical device structure */ /* logical device structure */
@ -234,23 +236,16 @@ struct bcm5974 {
struct bt_data *bt_data; /* button transferred data */ struct bt_data *bt_data; /* button transferred data */
struct urb *tp_urb; /* trackpad usb request block */ struct urb *tp_urb; /* trackpad usb request block */
u8 *tp_data; /* trackpad transferred data */ u8 *tp_data; /* trackpad transferred data */
int fingers; /* number of fingers on trackpad */ const struct tp_finger *index[MAX_FINGERS]; /* finger index data */
struct input_mt_pos pos[MAX_FINGERS]; /* position array */
int slots[MAX_FINGERS]; /* slot assignments */
}; };
/* logical dimensions */
#define DIM_PRESSURE 256 /* maximum finger pressure */
#define DIM_WIDTH 16 /* maximum finger width */
#define DIM_X 1280 /* maximum trackpad x value */
#define DIM_Y 800 /* maximum trackpad y value */
/* logical signal quality */ /* logical signal quality */
#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
#define SN_WIDTH 100 /* width signal-to-noise ratio */ #define SN_WIDTH 25 /* width signal-to-noise ratio */
#define SN_COORD 250 /* coordinate signal-to-noise ratio */ #define SN_COORD 250 /* coordinate signal-to-noise ratio */
#define SN_ORIENT 10 /* orientation signal-to-noise ratio */
/* pressure thresholds */
#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
#define PRESSURE_HIGH (3 * PRESSURE_LOW)
/* device constants */ /* device constants */
static const struct bcm5974_config bcm5974_config_table[] = { static const struct bcm5974_config bcm5974_config_table[] = {
@ -261,10 +256,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
0, 0,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, { SN_PRESSURE, 0, 256 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4824, 5342 }, { SN_COORD, -4824, 5342 },
{ DIM_Y, DIM_Y / SN_COORD, -172, 5820 } { SN_COORD, -172, 5820 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
@ -273,10 +269,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
0, 0,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, { SN_PRESSURE, 0, 256 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4824, 4824 }, { SN_COORD, -4824, 4824 },
{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 } { SN_COORD, -172, 4290 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI,
@ -285,10 +282,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4460, 5166 }, { SN_COORD, -4460, 5166 },
{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 } { SN_COORD, -75, 6700 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
@ -297,10 +295,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 }, { SN_COORD, -4620, 5140 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 } { SN_COORD, -150, 6600 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
@ -309,10 +308,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4616, 5112 }, { SN_COORD, -4616, 5112 },
{ DIM_Y, DIM_Y / SN_COORD, -142, 5234 } { SN_COORD, -142, 5234 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
@ -321,10 +321,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4415, 5050 }, { SN_COORD, -4415, 5050 },
{ DIM_Y, DIM_Y / SN_COORD, -55, 6680 } { SN_COORD, -55, 6680 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
@ -333,10 +334,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 }, { SN_COORD, -4620, 5140 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 } { SN_COORD, -150, 6600 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
@ -345,10 +347,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4750, 5280 }, { SN_COORD, -4750, 5280 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 } { SN_COORD, -150, 6730 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
@ -357,10 +360,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 }, { SN_COORD, -4620, 5140 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 } { SN_COORD, -150, 6600 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{ {
USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
@ -369,10 +373,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
HAS_INTEGRATED_BUTTON, HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data), 0x84, sizeof(struct bt_data),
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, { SN_PRESSURE, 0, 300 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4750, 5280 }, { SN_COORD, -4750, 5280 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 } { SN_COORD, -150, 6730 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
}, },
{} {}
}; };
@ -396,18 +401,11 @@ static inline int raw2int(__le16 x)
return (signed short)le16_to_cpu(x); return (signed short)le16_to_cpu(x);
} }
/* scale device data to logical dimensions (asserts devmin < devmax) */ static void set_abs(struct input_dev *input, unsigned int code,
static inline int int2scale(const struct bcm5974_param *p, int x) const struct bcm5974_param *p)
{ {
return x * p->dim / (p->devmax - p->devmin); int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0;
} input_set_abs_params(input, code, p->min, p->max, fuzz, 0);
/* all logical value ranges are [0,dim). */
static inline int int2bound(const struct bcm5974_param *p, int x)
{
int s = int2scale(p, x);
return clamp_val(s, 0, p->dim - 1);
} }
/* setup which logical events to report */ /* setup which logical events to report */
@ -416,48 +414,30 @@ static void setup_events_to_report(struct input_dev *input_dev,
{ {
__set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_PRESSURE, /* for synaptics only */
0, cfg->p.dim, cfg->p.fuzz, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0);
input_set_abs_params(input_dev, ABS_TOOL_WIDTH, input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0);
0, cfg->w.dim, cfg->w.fuzz, 0);
input_set_abs_params(input_dev, ABS_X,
0, cfg->x.dim, cfg->x.fuzz, 0);
input_set_abs_params(input_dev, ABS_Y,
0, cfg->y.dim, cfg->y.fuzz, 0);
/* finger touch area */ /* finger touch area */
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
cfg->w.devmin, cfg->w.devmax, 0, 0); set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
cfg->w.devmin, cfg->w.devmax, 0, 0);
/* finger approach area */ /* finger approach area */
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
cfg->w.devmin, cfg->w.devmax, 0, 0); set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
cfg->w.devmin, cfg->w.devmax, 0, 0);
/* finger orientation */ /* finger orientation */
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
-MAX_FINGER_ORIENTATION,
MAX_FINGER_ORIENTATION, 0, 0);
/* finger position */ /* finger position */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x);
cfg->x.devmin, cfg->x.devmax, 0, 0); set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
cfg->y.devmin, cfg->y.devmax, 0, 0);
__set_bit(EV_KEY, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit); __set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (cfg->caps & HAS_INTEGRATED_BUTTON) if (cfg->caps & HAS_INTEGRATED_BUTTON)
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
input_set_events_per_packet(input_dev, 60); input_mt_init_slots(input_dev, MAX_FINGERS,
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
} }
/* report button data as logical button state */ /* report button data as logical button state */
@ -477,24 +457,44 @@ static int report_bt_state(struct bcm5974 *dev, int size)
return 0; return 0;
} }
static void report_finger_data(struct input_dev *input, static void report_finger_data(struct input_dev *input, int slot,
const struct bcm5974_config *cfg, const struct input_mt_pos *pos,
const struct tp_finger *f) const struct tp_finger *f)
{ {
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, input_report_abs(input, ABS_MT_TOUCH_MAJOR,
raw2int(f->force_major) << 1); raw2int(f->touch_major) << 1);
input_report_abs(input, ABS_MT_TOUCH_MINOR, input_report_abs(input, ABS_MT_TOUCH_MINOR,
raw2int(f->force_minor) << 1); raw2int(f->touch_minor) << 1);
input_report_abs(input, ABS_MT_WIDTH_MAJOR, input_report_abs(input, ABS_MT_WIDTH_MAJOR,
raw2int(f->size_major) << 1); raw2int(f->tool_major) << 1);
input_report_abs(input, ABS_MT_WIDTH_MINOR, input_report_abs(input, ABS_MT_WIDTH_MINOR,
raw2int(f->size_minor) << 1); raw2int(f->tool_minor) << 1);
input_report_abs(input, ABS_MT_ORIENTATION, input_report_abs(input, ABS_MT_ORIENTATION,
MAX_FINGER_ORIENTATION - raw2int(f->orientation)); MAX_FINGER_ORIENTATION - raw2int(f->orientation));
input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x)); input_report_abs(input, ABS_MT_POSITION_X, pos->x);
input_report_abs(input, ABS_MT_POSITION_Y, input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y)); }
input_mt_sync(input);
static void report_synaptics_data(struct input_dev *input,
const struct bcm5974_config *cfg,
const struct tp_finger *f, int raw_n)
{
int abs_p = 0, abs_w = 0;
if (raw_n) {
int p = raw2int(f->touch_major);
int w = raw2int(f->tool_major);
if (p > 0 && raw2int(f->origin)) {
abs_p = clamp_val(256 * p / cfg->p.max, 0, 255);
abs_w = clamp_val(16 * w / cfg->w.max, 0, 15);
}
}
input_report_abs(input, ABS_PRESSURE, abs_p);
input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
} }
/* report trackpad data as logical trackpad state */ /* report trackpad data as logical trackpad state */
@ -503,9 +503,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
const struct bcm5974_config *c = &dev->cfg; const struct bcm5974_config *c = &dev->cfg;
const struct tp_finger *f; const struct tp_finger *f;
struct input_dev *input = dev->input; struct input_dev *input = dev->input;
int raw_p, raw_w, raw_x, raw_y, raw_n, i; int raw_n, i, n = 0;
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
return -EIO; return -EIO;
@ -514,76 +512,29 @@ static int report_tp_state(struct bcm5974 *dev, int size)
f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
raw_n = (size - c->tp_offset) / SIZEOF_FINGER; raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
/* always track the first finger; when detached, start over */ for (i = 0; i < raw_n; i++) {
if (raw_n) { if (raw2int(f[i].touch_major) == 0)
continue;
/* report raw trackpad data */ dev->pos[n].x = raw2int(f[i].abs_x);
for (i = 0; i < raw_n; i++) dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
report_finger_data(input, c, &f[i]); dev->index[n++] = &f[i];
raw_p = raw2int(f->force_major);
raw_w = raw2int(f->size_major);
raw_x = raw2int(f->abs_x);
raw_y = raw2int(f->abs_y);
dprintk(9,
"bcm5974: "
"raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
raw_p, raw_w, raw_x, raw_y, raw_n);
ptest = int2bound(&c->p, raw_p);
origin = raw2int(f->origin);
/* while tracking finger still valid, count all fingers */
if (ptest > PRESSURE_LOW && origin) {
abs_p = ptest;
abs_w = int2bound(&c->w, raw_w);
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
while (raw_n--) {
ptest = int2bound(&c->p,
raw2int(f->force_major));
if (ptest > PRESSURE_LOW)
nmax++;
if (ptest > PRESSURE_HIGH)
nmin++;
f++;
}
}
} }
/* set the integrated button if applicable */ input_mt_assign_slots(input, dev->slots, dev->pos, n);
if (c->tp_type == TYPE2)
ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
if (dev->fingers < nmin) for (i = 0; i < n; i++)
dev->fingers = nmin; report_finger_data(input, dev->slots[i],
if (dev->fingers > nmax) &dev->pos[i], dev->index[i]);
dev->fingers = nmax;
input_report_key(input, BTN_TOUCH, dev->fingers > 0); input_mt_sync_frame(input);
input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3);
input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3);
input_report_abs(input, ABS_PRESSURE, abs_p); report_synaptics_data(input, c, f, raw_n);
input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
if (abs_p) {
input_report_abs(input, ABS_X, abs_x);
input_report_abs(input, ABS_Y, abs_y);
dprintk(8,
"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
"nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w,
abs_x, abs_y, nmin, nmax, dev->fingers, ibt);
}
/* type 2 reports button events via ibt only */ /* type 2 reports button events via ibt only */
if (c->tp_type == TYPE2) if (c->tp_type == TYPE2) {
int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
input_report_key(input, BTN_LEFT, ibt); input_report_key(input, BTN_LEFT, ibt);
}
input_sync(input); input_sync(input);
@ -742,9 +693,11 @@ static int bcm5974_start_traffic(struct bcm5974 *dev)
goto err_out; goto err_out;
} }
error = usb_submit_urb(dev->bt_urb, GFP_KERNEL); if (dev->bt_urb) {
if (error) error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
goto err_reset_mode; if (error)
goto err_reset_mode;
}
error = usb_submit_urb(dev->tp_urb, GFP_KERNEL); error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
if (error) if (error)
@ -868,19 +821,23 @@ static int bcm5974_probe(struct usb_interface *iface,
mutex_init(&dev->pm_mutex); mutex_init(&dev->pm_mutex);
/* setup urbs */ /* setup urbs */
dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); if (cfg->tp_type == TYPE1) {
if (!dev->bt_urb) dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
goto err_free_devs; if (!dev->bt_urb)
goto err_free_devs;
}
dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->tp_urb) if (!dev->tp_urb)
goto err_free_bt_urb; goto err_free_bt_urb;
dev->bt_data = usb_alloc_coherent(dev->udev, if (dev->bt_urb) {
dev->bt_data = usb_alloc_coherent(dev->udev,
dev->cfg.bt_datalen, GFP_KERNEL, dev->cfg.bt_datalen, GFP_KERNEL,
&dev->bt_urb->transfer_dma); &dev->bt_urb->transfer_dma);
if (!dev->bt_data) if (!dev->bt_data)
goto err_free_urb; goto err_free_urb;
}
dev->tp_data = usb_alloc_coherent(dev->udev, dev->tp_data = usb_alloc_coherent(dev->udev,
dev->cfg.tp_datalen, GFP_KERNEL, dev->cfg.tp_datalen, GFP_KERNEL,
@ -888,10 +845,11 @@ static int bcm5974_probe(struct usb_interface *iface,
if (!dev->tp_data) if (!dev->tp_data)
goto err_free_bt_buffer; goto err_free_bt_buffer;
usb_fill_int_urb(dev->bt_urb, udev, if (dev->bt_urb)
usb_rcvintpipe(udev, cfg->bt_ep), usb_fill_int_urb(dev->bt_urb, udev,
dev->bt_data, dev->cfg.bt_datalen, usb_rcvintpipe(udev, cfg->bt_ep),
bcm5974_irq_button, dev, 1); dev->bt_data, dev->cfg.bt_datalen,
bcm5974_irq_button, dev, 1);
usb_fill_int_urb(dev->tp_urb, udev, usb_fill_int_urb(dev->tp_urb, udev,
usb_rcvintpipe(udev, cfg->tp_ep), usb_rcvintpipe(udev, cfg->tp_ep),
@ -929,8 +887,9 @@ static int bcm5974_probe(struct usb_interface *iface,
usb_free_coherent(dev->udev, dev->cfg.tp_datalen, usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
dev->tp_data, dev->tp_urb->transfer_dma); dev->tp_data, dev->tp_urb->transfer_dma);
err_free_bt_buffer: err_free_bt_buffer:
usb_free_coherent(dev->udev, dev->cfg.bt_datalen, if (dev->bt_urb)
dev->bt_data, dev->bt_urb->transfer_dma); usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
dev->bt_data, dev->bt_urb->transfer_dma);
err_free_urb: err_free_urb:
usb_free_urb(dev->tp_urb); usb_free_urb(dev->tp_urb);
err_free_bt_urb: err_free_bt_urb:
@ -951,8 +910,9 @@ static void bcm5974_disconnect(struct usb_interface *iface)
input_unregister_device(dev->input); input_unregister_device(dev->input);
usb_free_coherent(dev->udev, dev->cfg.tp_datalen, usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
dev->tp_data, dev->tp_urb->transfer_dma); dev->tp_data, dev->tp_urb->transfer_dma);
usb_free_coherent(dev->udev, dev->cfg.bt_datalen, if (dev->bt_urb)
dev->bt_data, dev->bt_urb->transfer_dma); usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
dev->bt_data, dev->bt_urb->transfer_dma);
usb_free_urb(dev->tp_urb); usb_free_urb(dev->tp_urb);
usb_free_urb(dev->bt_urb); usb_free_urb(dev->bt_urb);
kfree(dev); kfree(dev);

View File

@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
} }
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break; break;
@ -1035,7 +1035,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
/* Multitouch capable pad, up to 5 fingers. */ /* Multitouch capable pad, up to 5 fingers. */
input_mt_init_slots(dev, ETP_MAX_FINGERS); input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);

View File

@ -960,7 +960,7 @@ static int fsp_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
} }

View File

@ -1232,7 +1232,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X, set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y); ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */ /* Image sensors can report per-contact pressure */
@ -1244,7 +1244,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
/* Non-image sensors with AGM use semi-mt */ /* Non-image sensors with AGM use semi-mt */
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit); __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X, set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y); ABS_MT_POSITION_Y);
} }

View File

@ -1530,7 +1530,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0); 0, 255, 0, 0);
@ -1575,7 +1575,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case TABLETPC2FG: case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) { if (features->device_type == BTN_TOOL_FINGER) {
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0); 0, MT_TOOL_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@ -1631,7 +1631,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit); __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP, __set_bit(BTN_TOOL_TRIPLETAP,

View File

@ -1152,7 +1152,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
/* For multi touch */ /* For multi touch */
num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
error = input_mt_init_slots(input_dev, num_mt_slots); error = input_mt_init_slots(input_dev, num_mt_slots, 0);
if (error) if (error)
goto err_free_object; goto err_free_object;
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,

View File

@ -571,7 +571,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, CY_MAXZ, 0, 0); 0, CY_MAXZ, 0, 0);
input_mt_init_slots(input_dev, CY_MAX_ID); input_mt_init_slots(input_dev, CY_MAX_ID, 0);
error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,

View File

@ -778,7 +778,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
0, tsdata->num_x * 64 - 1, 0, 0); 0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0); 0, tsdata->num_y * 64 - 1, 0, 0);
error = input_mt_init_slots(input, MAX_SUPPORT_POINTS); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
if (error) { if (error) {
dev_err(&client->dev, "Unable to init MT slots.\n"); dev_err(&client->dev, "Unable to init MT slots.\n");
goto err_free_mem; goto err_free_mem;

View File

@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0); ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS); input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
input_set_drvdata(input_dev, ts); input_set_drvdata(input_dev, ts);

View File

@ -252,7 +252,7 @@ static int __devinit ili210x_i2c_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
/* Multi touch */ /* Multi touch */
input_mt_init_slots(input, MAX_TOUCHES); input_mt_init_slots(input, MAX_TOUCHES, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);

View File

@ -404,7 +404,7 @@ static int __devinit mms114_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0);
/* For multi touch */ /* For multi touch */
input_mt_init_slots(input_dev, MMS114_MAX_TOUCH); input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MMS114_MAX_AREA, 0, 0); 0, MMS114_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, input_set_abs_params(input_dev, ABS_MT_POSITION_X,

View File

@ -264,7 +264,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
if (pm->maxcontacts > 1) { if (pm->maxcontacts > 1) {
input_mt_init_slots(pm->dev, pm->maxcontacts); input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
input_set_abs_params(pm->dev, input_set_abs_params(pm->dev,
ABS_MT_POSITION_X, 0, max_x, 0, 0); ABS_MT_POSITION_X, 0, max_x, 0, 0);
input_set_abs_params(pm->dev, input_set_abs_params(pm->dev,

View File

@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001)
case 5: case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG; w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0); 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, input_set_abs_params(dev, ABS_MT_POSITION_Y,

View File

@ -414,7 +414,7 @@ struct hid_field {
__u16 dpad; /* dpad input code */ __u16 dpad; /* dpad input code */
}; };
#define HID_MAX_FIELDS 128 #define HID_MAX_FIELDS 256
struct hid_report { struct hid_report {
struct list_head list; struct list_head list;
@ -626,6 +626,7 @@ struct hid_usage_id {
* @report_fixup: called before report descriptor parsing (NULL means nop) * @report_fixup: called before report descriptor parsing (NULL means nop)
* @input_mapping: invoked on input registering before mapping an usage * @input_mapping: invoked on input registering before mapping an usage
* @input_mapped: invoked on input registering after mapping an usage * @input_mapped: invoked on input registering after mapping an usage
* @input_configured: invoked just before the device is registered
* @feature_mapping: invoked on feature registering * @feature_mapping: invoked on feature registering
* @suspend: invoked on suspend (NULL means nop) * @suspend: invoked on suspend (NULL means nop)
* @resume: invoked on resume if device was not reset (NULL means nop) * @resume: invoked on resume if device was not reset (NULL means nop)
@ -670,6 +671,8 @@ struct hid_driver {
int (*input_mapped)(struct hid_device *hdev, int (*input_mapped)(struct hid_device *hdev,
struct hid_input *hidinput, struct hid_field *field, struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max); struct hid_usage *usage, unsigned long **bit, int *max);
void (*input_configured)(struct hid_device *hdev,
struct hid_input *hidinput);
void (*feature_mapping)(struct hid_device *hdev, void (*feature_mapping)(struct hid_device *hdev,
struct hid_field *field, struct hid_field *field,
struct hid_usage *usage); struct hid_usage *usage);

View File

@ -1168,6 +1168,18 @@ struct ff_effect {
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
/**
* struct input_value - input value representation
* @type: type of value (EV_KEY, EV_ABS, etc)
* @code: the value code
* @value: the value
*/
struct input_value {
__u16 type;
__u16 code;
__s32 value;
};
/** /**
* struct input_dev - represents an input device * struct input_dev - represents an input device
* @name: name of the device * @name: name of the device
@ -1203,11 +1215,7 @@ struct ff_effect {
* software autorepeat * software autorepeat
* @timer: timer for software autorepeat * @timer: timer for software autorepeat
* @rep: current values for autorepeat parameters (delay, rate) * @rep: current values for autorepeat parameters (delay, rate)
* @mt: pointer to array of struct input_mt_slot holding current values * @mt: pointer to multitouch state
* of tracked contacts
* @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted
* @trkid: stores MT tracking ID for the current contact
* @absinfo: array of &struct input_absinfo elements holding information * @absinfo: array of &struct input_absinfo elements holding information
* about absolute axes (current value, min, max, flat, fuzz, * about absolute axes (current value, min, max, flat, fuzz,
* resolution) * resolution)
@ -1244,7 +1252,6 @@ struct ff_effect {
* last user closes the device * last user closes the device
* @going_away: marks devices that are in a middle of unregistering and * @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV. * causes input_open_device*() fail with -ENODEV.
* @sync: set to %true when there were no new events since last EV_SYN
* @dev: driver model's view of this device * @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When * @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held * accessing the list dev->mutex must be held
@ -1287,10 +1294,7 @@ struct input_dev {
int rep[REP_CNT]; int rep[REP_CNT];
struct input_mt_slot *mt; struct input_mt *mt;
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo; struct input_absinfo *absinfo;
@ -1312,12 +1316,14 @@ struct input_dev {
unsigned int users; unsigned int users;
bool going_away; bool going_away;
bool sync;
struct device dev; struct device dev;
struct list_head h_list; struct list_head h_list;
struct list_head node; struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
}; };
#define to_input_dev(d) container_of(d, struct input_dev, dev) #define to_input_dev(d) container_of(d, struct input_dev, dev)
@ -1378,6 +1384,9 @@ struct input_handle;
* @event: event handler. This method is being called by input core with * @event: event handler. This method is being called by input core with
* interrupts disabled and dev->event_lock spinlock held and so * interrupts disabled and dev->event_lock spinlock held and so
* it may not sleep * it may not sleep
* @events: event sequence handler. This method is being called by
* input core with interrupts disabled and dev->event_lock
* spinlock held and so it may not sleep
* @filter: similar to @event; separates normal event handlers from * @filter: similar to @event; separates normal event handlers from
* "filters". * "filters".
* @match: called after comparing device's id with handler's id_table * @match: called after comparing device's id with handler's id_table
@ -1414,6 +1423,8 @@ struct input_handler {
void *private; void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
bool (*match)(struct input_handler *handler, struct input_dev *dev); bool (*match)(struct input_handler *handler, struct input_dev *dev);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

View File

@ -15,12 +15,41 @@
#define TRKID_MAX 0xffff #define TRKID_MAX 0xffff
#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
/** /**
* struct input_mt_slot - represents the state of an input MT slot * struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot * @abs: holds current values of ABS_MT axes for this slot
* @frame: last frame at which input_mt_report_slot_state() was called
* @key: optional driver designation of this slot
*/ */
struct input_mt_slot { struct input_mt_slot {
int abs[ABS_MT_LAST - ABS_MT_FIRST + 1]; int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
unsigned int frame;
unsigned int key;
};
/**
* struct input_mt - state of tracked contacts
* @trkid: stores MT tracking ID for the next contact
* @num_slots: number of MT slots the device uses
* @slot: MT slot currently being transmitted
* @flags: input_mt operation flags
* @frame: increases every time input_mt_sync_frame() is called
* @red: reduced cost matrix for in-kernel tracking
* @slots: array of slots holding current values of tracked contacts
*/
struct input_mt {
int trkid;
int num_slots;
int slot;
unsigned int flags;
unsigned int frame;
int *red;
struct input_mt_slot slots[];
}; };
static inline void input_mt_set_value(struct input_mt_slot *slot, static inline void input_mt_set_value(struct input_mt_slot *slot,
@ -35,12 +64,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
return slot->abs[code - ABS_MT_FIRST]; return slot->abs[code - ABS_MT_FIRST];
} }
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots); static inline bool input_mt_is_active(const struct input_mt_slot *slot)
{
return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0;
}
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags);
void input_mt_destroy_slots(struct input_dev *dev); void input_mt_destroy_slots(struct input_dev *dev);
static inline int input_mt_new_trkid(struct input_dev *dev) static inline int input_mt_new_trkid(struct input_mt *mt)
{ {
return dev->trkid++ & TRKID_MAX; return mt->trkid++ & TRKID_MAX;
} }
static inline void input_mt_slot(struct input_dev *dev, int slot) static inline void input_mt_slot(struct input_dev *dev, int slot)
@ -64,4 +99,20 @@ void input_mt_report_slot_state(struct input_dev *dev,
void input_mt_report_finger_count(struct input_dev *dev, int count); void input_mt_report_finger_count(struct input_dev *dev, int count);
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count); void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
void input_mt_sync_frame(struct input_dev *dev);
/**
* struct input_mt_pos - contact position
* @x: horizontal coordinate
* @y: vertical coordinate
*/
struct input_mt_pos {
s16 x, y;
};
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos);
int input_mt_get_slot_by_key(struct input_dev *dev, int key);
#endif #endif