Merge branch 'next' into for-linus
Prepare second set of updates for 3.7 merge window (Wacom driver update and patches extending number of input minors).
This commit is contained in:
Коммит
0cc8d6a9d2
|
@ -283,6 +283,9 @@
|
|||
#define USB_VENDOR_ID_EMS 0x2006
|
||||
#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_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
|
||||
|
||||
|
|
|
@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid)
|
|||
|
||||
int hidinput_connect(struct hid_device *hid, unsigned int force)
|
||||
{
|
||||
struct hid_driver *drv = hid->driver;
|
||||
struct hid_report *report;
|
||||
struct hid_input *hidinput = NULL;
|
||||
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
|
||||
* same interface. */
|
||||
hidinput->report = report;
|
||||
if (drv->input_configured)
|
||||
drv->input_configured(hid, hidinput);
|
||||
if (input_register_device(hidinput->input))
|
||||
goto out_cleanup;
|
||||
hidinput = NULL;
|
||||
|
@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
}
|
||||
}
|
||||
|
||||
if (hidinput && input_register_device(hidinput->input))
|
||||
goto out_cleanup;
|
||||
if (hidinput) {
|
||||
if (drv->input_configured)
|
||||
drv->input_configured(hid, hidinput);
|
||||
if (input_register_device(hidinput->input))
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
|||
|
||||
__set_bit(EV_ABS, input->evbit);
|
||||
|
||||
error = input_mt_init_slots(input, 16);
|
||||
error = input_mt_init_slots(input, 16, 0);
|
||||
if (error)
|
||||
return error;
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
|
||||
|
|
|
@ -51,12 +51,12 @@ MODULE_LICENSE("GPL");
|
|||
#define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
|
||||
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
|
||||
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
|
||||
#define MT_QUIRK_NO_AREA (1 << 9)
|
||||
|
||||
struct mt_slot {
|
||||
__s32 x, y, p, w, h;
|
||||
__s32 contactid; /* the device ContactID assigned to this slot */
|
||||
bool touch_state; /* is the touch valid? */
|
||||
bool seen_in_this_frame;/* has this slot been updated */
|
||||
};
|
||||
|
||||
struct mt_class {
|
||||
|
@ -92,8 +92,9 @@ struct mt_device {
|
|||
__u8 touches_by_report; /* how many touches are present in one report:
|
||||
* 1 means we should use a serial protocol
|
||||
* > 1 means hybrid (multitouch) protocol */
|
||||
bool serial_maybe; /* need to check for serial protocol */
|
||||
bool curvalid; /* is the current contact valid? */
|
||||
struct mt_slot *slots;
|
||||
unsigned mt_flags; /* flags to pass to input-mt */
|
||||
};
|
||||
|
||||
/* classes of device behavior */
|
||||
|
@ -115,6 +116,7 @@ struct mt_device {
|
|||
#define MT_CLS_EGALAX_SERIAL 0x0104
|
||||
#define MT_CLS_TOPSEED 0x0105
|
||||
#define MT_CLS_PANASONIC 0x0106
|
||||
#define MT_CLS_FLATFROG 0x0107
|
||||
|
||||
#define MT_DEFAULT_MAXCONTACT 10
|
||||
|
||||
|
@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td)
|
|||
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[] = {
|
||||
{ .name = MT_CLS_DEFAULT,
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
|
||||
|
@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = {
|
|||
MT_QUIRK_SLOT_IS_CONTACTID,
|
||||
.sn_move = 2048,
|
||||
.sn_width = 128,
|
||||
.sn_height = 128 },
|
||||
.sn_height = 128,
|
||||
.maxcontacts = 60,
|
||||
},
|
||||
{ .name = MT_CLS_CYPRESS,
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
||||
MT_QUIRK_CYPRESS,
|
||||
|
@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = {
|
|||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
|
||||
.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
|
||||
* such as Mouse that might have the same GenericDesktop usages. */
|
||||
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)
|
||||
return 0;
|
||||
|
||||
/* In case of an indirect device (touchpad), we need to add
|
||||
* specific BTN_TOOL_* to be handled by the synaptics xorg
|
||||
* driver.
|
||||
* We also consider that touchscreens providing buttons are touchpads.
|
||||
/*
|
||||
* Model touchscreens providing buttons as touchpads.
|
||||
*/
|
||||
if (field->application == HID_DG_TOUCHPAD ||
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON ||
|
||||
cls->is_indirect) {
|
||||
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);
|
||||
}
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
|
||||
td->mt_flags |= INPUT_MT_POINTER;
|
||||
|
||||
/* eGalax devices provide a Digitizer.Stylus input which overrides
|
||||
* 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);
|
||||
set_abs(hi->input, ABS_MT_POSITION_X, field,
|
||||
cls->sn_move);
|
||||
/* touchscreen emulation */
|
||||
set_abs(hi->input, ABS_X, field, cls->sn_move);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
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);
|
||||
set_abs(hi->input, ABS_MT_POSITION_Y, field,
|
||||
cls->sn_move);
|
||||
/* touchscreen emulation */
|
||||
set_abs(hi->input, ABS_Y, field, cls->sn_move);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
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;
|
||||
return 1;
|
||||
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);
|
||||
td->last_field_index = field->index;
|
||||
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:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
EV_ABS, ABS_MT_TOUCH_MAJOR);
|
||||
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
|
||||
cls->sn_width);
|
||||
if (!(cls->quirks & MT_QUIRK_NO_AREA))
|
||||
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
|
||||
cls->sn_width);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_HEIGHT:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
EV_ABS, ABS_MT_TOUCH_MINOR);
|
||||
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
||||
cls->sn_height);
|
||||
input_set_abs_params(hi->input,
|
||||
if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
|
||||
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
||||
cls->sn_height);
|
||||
input_set_abs_params(hi->input,
|
||||
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
}
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
|
@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
EV_ABS, ABS_MT_PRESSURE);
|
||||
set_abs(hi->input, ABS_MT_PRESSURE, field,
|
||||
cls->sn_pressure);
|
||||
/* touchscreen emulation */
|
||||
set_abs(hi->input, ABS_PRESSURE, field,
|
||||
cls->sn_pressure);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
|
@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|||
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;
|
||||
|
||||
|
@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td)
|
|||
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
|
||||
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,
|
||||
* 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) {
|
||||
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)
|
||||
td->slots[slotnum] = td->curdata;
|
||||
}
|
||||
td->num_received++;
|
||||
}
|
||||
if (slotnum < 0 || slotnum >= td->maxcontacts)
|
||||
return;
|
||||
|
||||
|
||||
/*
|
||||
* 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_slot(input, slotnum);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER,
|
||||
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_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);
|
||||
td->num_received = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
__s32 quirks = td->mtclass.quirks;
|
||||
|
||||
if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
|
||||
if (hid->claimed & HID_CLAIMED_INPUT) {
|
||||
switch (usage->hid) {
|
||||
case HID_DG_INRANGE:
|
||||
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)
|
||||
mt_complete_slot(td);
|
||||
mt_complete_slot(td, field->hidinput->input);
|
||||
|
||||
if (field->index == td->last_field_index
|
||||
&& 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)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
|
||||
td->serial_maybe = true;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
|
@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
if (ret)
|
||||
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);
|
||||
|
||||
mt_set_maxcontacts(hdev);
|
||||
|
@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev)
|
|||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
|
||||
hid_hw_stop(hdev);
|
||||
kfree(td->slots);
|
||||
kfree(td);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = {
|
|||
MT_USB_DEVICE(USB_VENDOR_ID_ELO,
|
||||
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 */
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
|
||||
|
@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = {
|
|||
.remove = mt_remove,
|
||||
.input_mapping = mt_input_mapping,
|
||||
.input_mapped = mt_input_mapped,
|
||||
.input_configured = mt_input_configured,
|
||||
.feature_mapping = mt_feature_mapping,
|
||||
.usage_table = mt_grabbed_usages,
|
||||
.event = mt_event,
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
#include <linux/input/mt.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
#include "input-compat.h"
|
||||
|
||||
struct evdev {
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct evdev_client __rcu *grab;
|
||||
|
@ -35,6 +35,7 @@ struct evdev {
|
|||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
struct cdev cdev;
|
||||
bool exist;
|
||||
};
|
||||
|
||||
|
@ -51,19 +52,9 @@ struct evdev_client {
|
|||
struct input_event buffer[];
|
||||
};
|
||||
|
||||
static struct evdev *evdev_table[EVDEV_MINORS];
|
||||
static DEFINE_MUTEX(evdev_table_mutex);
|
||||
|
||||
static void evdev_pass_event(struct evdev_client *client,
|
||||
struct input_event *event,
|
||||
ktime_t mono, ktime_t real)
|
||||
static void __pass_event(struct evdev_client *client,
|
||||
const struct input_event *event)
|
||||
{
|
||||
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->head &= client->bufsize - 1;
|
||||
|
||||
|
@ -86,8 +77,63 @@ static void evdev_pass_event(struct evdev_client *client,
|
|||
client->packet_head = client->head;
|
||||
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);
|
||||
|
||||
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 +142,9 @@ static void evdev_pass_event(struct evdev_client *client,
|
|||
static void evdev_event(struct input_handle *handle,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct evdev *evdev = handle->private;
|
||||
struct evdev_client *client;
|
||||
struct input_event event;
|
||||
ktime_t time_mono, time_real;
|
||||
struct input_value vals[] = { { type, code, value } };
|
||||
|
||||
time_mono = ktime_get();
|
||||
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);
|
||||
evdev_events(handle, vals, 1);
|
||||
}
|
||||
|
||||
static int evdev_fasync(int fd, struct file *file, int on)
|
||||
|
@ -285,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
|
|||
|
||||
static int evdev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct evdev *evdev;
|
||||
struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
|
||||
unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
|
||||
struct evdev_client *client;
|
||||
int i = iminor(inode) - EVDEV_MINOR_BASE;
|
||||
unsigned int bufsize;
|
||||
int error;
|
||||
|
||||
if (i >= EVDEV_MINORS)
|
||||
return -ENODEV;
|
||||
|
||||
error = mutex_lock_interruptible(&evdev_table_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
evdev = evdev_table[i];
|
||||
if (evdev)
|
||||
get_device(&evdev->dev);
|
||||
mutex_unlock(&evdev_table_mutex);
|
||||
|
||||
if (!evdev)
|
||||
return -ENODEV;
|
||||
|
||||
bufsize = evdev_compute_buffer_size(evdev->handle.dev);
|
||||
|
||||
client = kzalloc(sizeof(struct evdev_client) +
|
||||
bufsize * sizeof(struct input_event),
|
||||
GFP_KERNEL);
|
||||
if (!client) {
|
||||
error = -ENOMEM;
|
||||
goto err_put_evdev;
|
||||
}
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
client->bufsize = bufsize;
|
||||
spin_lock_init(&client->buffer_lock);
|
||||
|
@ -327,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file)
|
|||
file->private_data = client;
|
||||
nonseekable_open(inode, file);
|
||||
|
||||
get_device(&evdev->dev);
|
||||
return 0;
|
||||
|
||||
err_free_client:
|
||||
evdev_detach_client(evdev, client);
|
||||
kfree(client);
|
||||
err_put_evdev:
|
||||
put_device(&evdev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -653,20 +656,22 @@ static int evdev_handle_mt_request(struct input_dev *dev,
|
|||
unsigned int size,
|
||||
int __user *ip)
|
||||
{
|
||||
const struct input_mt_slot *mt = dev->mt;
|
||||
const struct input_mt *mt = dev->mt;
|
||||
unsigned int code;
|
||||
int max_slots;
|
||||
int i;
|
||||
|
||||
if (get_user(code, &ip[0]))
|
||||
return -EFAULT;
|
||||
if (!input_is_mt_value(code))
|
||||
if (!mt || !input_is_mt_value(code))
|
||||
return -EINVAL;
|
||||
|
||||
max_slots = (size - sizeof(__u32)) / sizeof(__s32);
|
||||
for (i = 0; i < dev->mtsize && i < max_slots; i++)
|
||||
if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
|
||||
for (i = 0; i < mt->num_slots && i < max_slots; i++) {
|
||||
int value = input_mt_get_value(&mt->slots[i], code);
|
||||
if (put_user(value, &ip[1 + i]))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -915,26 +920,6 @@ static const struct file_operations evdev_fops = {
|
|||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static int evdev_install_chrdev(struct evdev *evdev)
|
||||
{
|
||||
/*
|
||||
* No need to do any locking here as calls to connect and
|
||||
* disconnect are serialized by the input core
|
||||
*/
|
||||
evdev_table[evdev->minor] = evdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void evdev_remove_chrdev(struct evdev *evdev)
|
||||
{
|
||||
/*
|
||||
* Lock evdev table to prevent race with evdev_open()
|
||||
*/
|
||||
mutex_lock(&evdev_table_mutex);
|
||||
evdev_table[evdev->minor] = NULL;
|
||||
mutex_unlock(&evdev_table_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark device non-existent. This disables writes, ioctls and
|
||||
* prevents new users from opening the device. Already posted
|
||||
|
@ -953,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev)
|
|||
|
||||
evdev_mark_dead(evdev);
|
||||
evdev_hangup(evdev);
|
||||
evdev_remove_chrdev(evdev);
|
||||
|
||||
cdev_del(&evdev->cdev);
|
||||
|
||||
/* evdev is marked dead so no one else accesses evdev->open */
|
||||
if (evdev->open) {
|
||||
|
@ -964,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev)
|
|||
|
||||
/*
|
||||
* Create new evdev device. Note that input core serializes calls
|
||||
* to connect and disconnect so we don't need to lock evdev_table here.
|
||||
* to connect and disconnect.
|
||||
*/
|
||||
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct evdev *evdev;
|
||||
int minor;
|
||||
int dev_no;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < EVDEV_MINORS; minor++)
|
||||
if (!evdev_table[minor])
|
||||
break;
|
||||
|
||||
if (minor == EVDEV_MINORS) {
|
||||
pr_err("no more free evdev devices\n");
|
||||
return -ENFILE;
|
||||
minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
|
||||
if (minor < 0) {
|
||||
error = minor;
|
||||
pr_err("failed to reserve new minor: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
|
||||
if (!evdev)
|
||||
return -ENOMEM;
|
||||
if (!evdev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_minor;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&evdev->client_list);
|
||||
spin_lock_init(&evdev->client_lock);
|
||||
mutex_init(&evdev->mutex);
|
||||
init_waitqueue_head(&evdev->wait);
|
||||
|
||||
dev_set_name(&evdev->dev, "event%d", minor);
|
||||
evdev->exist = true;
|
||||
evdev->minor = minor;
|
||||
|
||||
dev_no = minor;
|
||||
/* Normalize device number if it falls into legacy range */
|
||||
if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
|
||||
dev_no -= EVDEV_MINOR_BASE;
|
||||
dev_set_name(&evdev->dev, "event%d", dev_no);
|
||||
|
||||
evdev->handle.dev = input_get_device(dev);
|
||||
evdev->handle.name = dev_name(&evdev->dev);
|
||||
evdev->handle.handler = handler;
|
||||
evdev->handle.private = evdev;
|
||||
|
||||
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
|
||||
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
|
||||
evdev->dev.class = &input_class;
|
||||
evdev->dev.parent = &dev->dev;
|
||||
evdev->dev.release = evdev_free;
|
||||
|
@ -1010,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
if (error)
|
||||
goto err_free_evdev;
|
||||
|
||||
error = evdev_install_chrdev(evdev);
|
||||
cdev_init(&evdev->cdev, &evdev_fops);
|
||||
error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
|
||||
if (error)
|
||||
goto err_unregister_handle;
|
||||
|
||||
|
@ -1026,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
input_unregister_handle(&evdev->handle);
|
||||
err_free_evdev:
|
||||
put_device(&evdev->dev);
|
||||
err_free_minor:
|
||||
input_free_minor(minor);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1035,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle)
|
|||
|
||||
device_del(&evdev->dev);
|
||||
evdev_cleanup(evdev);
|
||||
input_free_minor(MINOR(evdev->dev.devt));
|
||||
input_unregister_handle(handle);
|
||||
put_device(&evdev->dev);
|
||||
}
|
||||
|
@ -1048,9 +1042,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids);
|
|||
|
||||
static struct input_handler evdev_handler = {
|
||||
.event = evdev_event,
|
||||
.events = evdev_events,
|
||||
.connect = evdev_connect,
|
||||
.disconnect = evdev_disconnect,
|
||||
.fops = &evdev_fops,
|
||||
.legacy_minors = true,
|
||||
.minor = EVDEV_MINOR_BASE,
|
||||
.name = "evdev",
|
||||
.id_table = evdev_ids,
|
||||
|
|
|
@ -14,6 +14,14 @@
|
|||
|
||||
#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
|
||||
* @dev: input device supporting MT events and finger tracking
|
||||
|
@ -25,29 +33,63 @@
|
|||
* May be called repeatedly. Returns -EINVAL if attempting to
|
||||
* 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;
|
||||
|
||||
if (!num_slots)
|
||||
return 0;
|
||||
if (dev->mt)
|
||||
return dev->mtsize != num_slots ? -EINVAL : 0;
|
||||
if (mt)
|
||||
return mt->num_slots != num_slots ? -EINVAL : 0;
|
||||
|
||||
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
|
||||
if (!dev->mt)
|
||||
return -ENOMEM;
|
||||
mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
|
||||
if (!mt)
|
||||
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_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' */
|
||||
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;
|
||||
err_mem:
|
||||
kfree(mt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
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)
|
||||
{
|
||||
kfree(dev->mt);
|
||||
if (dev->mt) {
|
||||
kfree(dev->mt->red);
|
||||
kfree(dev->mt);
|
||||
}
|
||||
dev->mt = NULL;
|
||||
dev->mtsize = 0;
|
||||
dev->slot = 0;
|
||||
dev->trkid = 0;
|
||||
}
|
||||
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,
|
||||
unsigned int tool_type, bool active)
|
||||
{
|
||||
struct input_mt_slot *mt;
|
||||
struct input_mt *mt = dev->mt;
|
||||
struct input_mt_slot *slot;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
mt = &dev->mt[dev->slot];
|
||||
id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
|
||||
if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
|
||||
id = input_mt_new_trkid(dev);
|
||||
id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
|
||||
if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
|
||||
id = input_mt_new_trkid(mt);
|
||||
|
||||
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
|
||||
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)
|
||||
{
|
||||
struct input_mt_slot *oldest = NULL;
|
||||
int oldid = dev->trkid;
|
||||
int count = 0;
|
||||
int i;
|
||||
struct input_mt *mt = dev->mt;
|
||||
struct input_mt_slot *oldest;
|
||||
int oldid, count, i;
|
||||
|
||||
for (i = 0; i < dev->mtsize; ++i) {
|
||||
struct input_mt_slot *ps = &dev->mt[i];
|
||||
if (!mt)
|
||||
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);
|
||||
|
||||
if (id < 0)
|
||||
|
@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
|
|||
if (oldest) {
|
||||
int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
|
||||
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_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 {
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -32,7 +33,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
|||
MODULE_DESCRIPTION("Input core");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define INPUT_DEVICES 256
|
||||
#define INPUT_MAX_CHAR_DEVICES 1024
|
||||
#define INPUT_FIRST_DYNAMIC_DEV 256
|
||||
static DEFINE_IDA(input_ida);
|
||||
|
||||
static LIST_HEAD(input_dev_list);
|
||||
static LIST_HEAD(input_handler_list);
|
||||
|
@ -45,7 +48,7 @@ static LIST_HEAD(input_handler_list);
|
|||
*/
|
||||
static DEFINE_MUTEX(input_mutex);
|
||||
|
||||
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,
|
||||
unsigned long *bm, unsigned int max)
|
||||
|
@ -69,79 +72,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
|
|||
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)
|
||||
{
|
||||
if (test_bit(EV_REP, dev->evbit) &&
|
||||
|
@ -158,14 +88,128 @@ static void input_stop_autorepeat(struct input_dev *dev)
|
|||
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_PASS_TO_HANDLERS 1
|
||||
#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)
|
||||
|
||||
static int input_handle_abs_event(struct input_dev *dev,
|
||||
unsigned int code, int *pval)
|
||||
{
|
||||
struct input_mt *mt = dev->mt;
|
||||
bool is_mt_event;
|
||||
int *pold;
|
||||
|
||||
|
@ -174,8 +218,8 @@ static int input_handle_abs_event(struct input_dev *dev,
|
|||
* "Stage" the event; we'll flush it later, when we
|
||||
* get actual touch data.
|
||||
*/
|
||||
if (*pval >= 0 && *pval < dev->mtsize)
|
||||
dev->slot = *pval;
|
||||
if (mt && *pval >= 0 && *pval < mt->num_slots)
|
||||
mt->slot = *pval;
|
||||
|
||||
return INPUT_IGNORE_EVENT;
|
||||
}
|
||||
|
@ -184,9 +228,8 @@ static int input_handle_abs_event(struct input_dev *dev,
|
|||
|
||||
if (!is_mt_event) {
|
||||
pold = &dev->absinfo[code].value;
|
||||
} else if (dev->mt) {
|
||||
struct input_mt_slot *mtslot = &dev->mt[dev->slot];
|
||||
pold = &mtslot->abs[code - ABS_MT_FIRST];
|
||||
} else if (mt) {
|
||||
pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
|
||||
} else {
|
||||
/*
|
||||
* Bypass filtering for multi-touch events when
|
||||
|
@ -205,16 +248,16 @@ static int input_handle_abs_event(struct input_dev *dev,
|
|||
}
|
||||
|
||||
/* Flush pending "slot" event */
|
||||
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
|
||||
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
|
||||
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
|
||||
if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
|
||||
input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
|
||||
return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
|
||||
}
|
||||
|
||||
return INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
|
||||
static void input_handle_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
static int input_get_disposition(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
int disposition = INPUT_IGNORE_EVENT;
|
||||
|
||||
|
@ -227,37 +270,34 @@ static void input_handle_event(struct input_dev *dev,
|
|||
break;
|
||||
|
||||
case SYN_REPORT:
|
||||
if (!dev->sync) {
|
||||
dev->sync = true;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
|
||||
break;
|
||||
case SYN_MT_REPORT:
|
||||
dev->sync = false;
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
|
||||
!!test_bit(code, dev->key) != value) {
|
||||
if (is_event_supported(code, dev->keybit, KEY_MAX)) {
|
||||
|
||||
if (value != 2) {
|
||||
__change_bit(code, dev->key);
|
||||
if (value)
|
||||
input_start_autorepeat(dev, code);
|
||||
else
|
||||
input_stop_autorepeat(dev);
|
||||
/* auto-repeat bypasses state updates */
|
||||
if (value == 2) {
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
break;
|
||||
}
|
||||
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
if (!!test_bit(code, dev->key) != !!value) {
|
||||
|
||||
__change_bit(code, dev->key);
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_SW:
|
||||
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);
|
||||
disposition = INPUT_PASS_TO_HANDLERS;
|
||||
|
@ -284,7 +324,7 @@ static void input_handle_event(struct input_dev *dev,
|
|||
|
||||
case EV_LED:
|
||||
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);
|
||||
disposition = INPUT_PASS_TO_ALL;
|
||||
|
@ -317,14 +357,48 @@ static void input_handle_event(struct input_dev *dev,
|
|||
break;
|
||||
}
|
||||
|
||||
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
|
||||
dev->sync = false;
|
||||
return disposition;
|
||||
}
|
||||
|
||||
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)
|
||||
dev->event(dev, type, code, value);
|
||||
|
||||
if (disposition & INPUT_PASS_TO_HANDLERS)
|
||||
input_pass_event(dev, type, code, value);
|
||||
if (!dev->vals)
|
||||
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 +426,6 @@ void input_event(struct input_dev *dev,
|
|||
if (is_event_supported(type, dev->evbit, EV_MAX)) {
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
add_input_randomness(type, code, value);
|
||||
input_handle_event(dev, type, code, value);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
@ -831,10 +904,12 @@ int input_set_keycode(struct input_dev *dev,
|
|||
if (test_bit(EV_KEY, dev->evbit) &&
|
||||
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
|
||||
__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);
|
||||
if (dev->sync)
|
||||
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
|
||||
input_pass_values(dev, vals, ARRAY_SIZE(vals));
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1144,7 +1219,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
|
|||
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
|
||||
if (handler->filter)
|
||||
seq_puts(seq, " (filter)");
|
||||
if (handler->fops)
|
||||
if (handler->legacy_minors)
|
||||
seq_printf(seq, " Minor=%d", handler->minor);
|
||||
seq_putc(seq, '\n');
|
||||
|
||||
|
@ -1425,6 +1500,7 @@ static void input_dev_release(struct device *device)
|
|||
input_ff_destroy(dev);
|
||||
input_mt_destroy_slots(dev);
|
||||
kfree(dev->absinfo);
|
||||
kfree(dev->vals);
|
||||
kfree(dev);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
|
@ -1760,8 +1836,8 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
|
|||
int i;
|
||||
unsigned int events;
|
||||
|
||||
if (dev->mtsize) {
|
||||
mt_slots = dev->mtsize;
|
||||
if (dev->mt) {
|
||||
mt_slots = dev->mt->num_slots;
|
||||
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
|
||||
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
|
||||
dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
|
||||
|
@ -1787,6 +1863,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
|
|||
if (test_bit(i, dev->relbit))
|
||||
events++;
|
||||
|
||||
/* Make room for KEY and MSC events */
|
||||
events += 7;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
|
@ -1825,6 +1904,7 @@ int input_register_device(struct input_dev *dev)
|
|||
{
|
||||
static atomic_t input_no = ATOMIC_INIT(0);
|
||||
struct input_handler *handler;
|
||||
unsigned int packet_size;
|
||||
const char *path;
|
||||
int error;
|
||||
|
||||
|
@ -1837,9 +1917,14 @@ int input_register_device(struct input_dev *dev)
|
|||
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
|
||||
input_cleanse_bitmasks(dev);
|
||||
|
||||
if (!dev->hint_events_per_packet)
|
||||
dev->hint_events_per_packet =
|
||||
input_estimate_events_per_packet(dev);
|
||||
packet_size = input_estimate_events_per_packet(dev);
|
||||
if (dev->hint_events_per_packet < packet_size)
|
||||
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
|
||||
|
@ -1932,22 +2017,14 @@ EXPORT_SYMBOL(input_unregister_device);
|
|||
int input_register_handler(struct input_handler *handler)
|
||||
{
|
||||
struct input_dev *dev;
|
||||
int retval;
|
||||
int error;
|
||||
|
||||
retval = mutex_lock_interruptible(&input_mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
error = mutex_lock_interruptible(&input_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
INIT_LIST_HEAD(&handler->h_list);
|
||||
|
||||
if (handler->fops != NULL) {
|
||||
if (input_table[handler->minor >> 5]) {
|
||||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
input_table[handler->minor >> 5] = handler;
|
||||
}
|
||||
|
||||
list_add_tail(&handler->node, &input_handler_list);
|
||||
|
||||
list_for_each_entry(dev, &input_dev_list, node)
|
||||
|
@ -1955,9 +2032,8 @@ int input_register_handler(struct input_handler *handler)
|
|||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
out:
|
||||
mutex_unlock(&input_mutex);
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(input_register_handler);
|
||||
|
||||
|
@ -1980,9 +2056,6 @@ void input_unregister_handler(struct input_handler *handler)
|
|||
|
||||
list_del_init(&handler->node);
|
||||
|
||||
if (handler->fops != NULL)
|
||||
input_table[handler->minor >> 5] = NULL;
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
mutex_unlock(&input_mutex);
|
||||
|
@ -2099,51 +2172,52 @@ void input_unregister_handle(struct input_handle *handle)
|
|||
}
|
||||
EXPORT_SYMBOL(input_unregister_handle);
|
||||
|
||||
static int input_open_file(struct inode *inode, struct file *file)
|
||||
/**
|
||||
* input_get_new_minor - allocates a new input minor number
|
||||
* @legacy_base: beginning or the legacy range to be searched
|
||||
* @legacy_num: size of legacy range
|
||||
* @allow_dynamic: whether we can also take ID from the dynamic range
|
||||
*
|
||||
* This function allocates a new device minor for from input major namespace.
|
||||
* Caller can request legacy minor by specifying @legacy_base and @legacy_num
|
||||
* parameters and whether ID can be allocated from dynamic range if there are
|
||||
* no free IDs in legacy range.
|
||||
*/
|
||||
int input_get_new_minor(int legacy_base, unsigned int legacy_num,
|
||||
bool allow_dynamic)
|
||||
{
|
||||
struct input_handler *handler;
|
||||
const struct file_operations *old_fops, *new_fops = NULL;
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&input_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* No load-on-demand here? */
|
||||
handler = input_table[iminor(inode) >> 5];
|
||||
if (handler)
|
||||
new_fops = fops_get(handler->fops);
|
||||
|
||||
mutex_unlock(&input_mutex);
|
||||
|
||||
/*
|
||||
* That's _really_ odd. Usually NULL ->open means "nothing special",
|
||||
* not "no device". Oh, well...
|
||||
* This function should be called from input handler's ->connect()
|
||||
* methods, which are serialized with input_mutex, so no additional
|
||||
* locking is needed here.
|
||||
*/
|
||||
if (!new_fops || !new_fops->open) {
|
||||
fops_put(new_fops);
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
if (legacy_base >= 0) {
|
||||
int minor = ida_simple_get(&input_ida,
|
||||
legacy_base,
|
||||
legacy_base + legacy_num,
|
||||
GFP_KERNEL);
|
||||
if (minor >= 0 || !allow_dynamic)
|
||||
return minor;
|
||||
}
|
||||
|
||||
old_fops = file->f_op;
|
||||
file->f_op = new_fops;
|
||||
|
||||
err = new_fops->open(inode, file);
|
||||
if (err) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
out:
|
||||
return err;
|
||||
return ida_simple_get(&input_ida,
|
||||
INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL(input_get_new_minor);
|
||||
|
||||
static const struct file_operations input_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = input_open_file,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
/**
|
||||
* input_free_minor - release previously allocated minor
|
||||
* @minor: minor to be released
|
||||
*
|
||||
* This function releases previously allocated input minor so that it can be
|
||||
* reused later.
|
||||
*/
|
||||
void input_free_minor(unsigned int minor)
|
||||
{
|
||||
ida_simple_remove(&input_ida, minor);
|
||||
}
|
||||
EXPORT_SYMBOL(input_free_minor);
|
||||
|
||||
static int __init input_init(void)
|
||||
{
|
||||
|
@ -2159,7 +2233,8 @@ static int __init input_init(void)
|
|||
if (err)
|
||||
goto fail1;
|
||||
|
||||
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
|
||||
err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
|
||||
INPUT_MAX_CHAR_DEVICES, "input");
|
||||
if (err) {
|
||||
pr_err("unable to register char major %d", INPUT_MAJOR);
|
||||
goto fail2;
|
||||
|
@ -2175,7 +2250,8 @@ static int __init input_init(void)
|
|||
static void __exit input_exit(void)
|
||||
{
|
||||
input_proc_exit();
|
||||
unregister_chrdev(INPUT_MAJOR, "input");
|
||||
unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),
|
||||
INPUT_MAX_CHAR_DEVICES);
|
||||
class_unregister(&input_class);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Joystick device interfaces");
|
||||
|
@ -39,13 +40,13 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
struct joydev {
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head client_list;
|
||||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
struct cdev cdev;
|
||||
bool exist;
|
||||
|
||||
struct js_corr corr[ABS_CNT];
|
||||
|
@ -70,9 +71,6 @@ struct joydev_client {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
static struct joydev *joydev_table[JOYDEV_MINORS];
|
||||
static DEFINE_MUTEX(joydev_table_mutex);
|
||||
|
||||
static int joydev_correct(int value, struct js_corr *corr)
|
||||
{
|
||||
switch (corr->type) {
|
||||
|
@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file)
|
|||
|
||||
static int joydev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct joydev *joydev =
|
||||
container_of(inode->i_cdev, struct joydev, cdev);
|
||||
struct joydev_client *client;
|
||||
struct joydev *joydev;
|
||||
int i = iminor(inode) - JOYDEV_MINOR_BASE;
|
||||
int error;
|
||||
|
||||
if (i >= JOYDEV_MINORS)
|
||||
return -ENODEV;
|
||||
|
||||
error = mutex_lock_interruptible(&joydev_table_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
joydev = joydev_table[i];
|
||||
if (joydev)
|
||||
get_device(&joydev->dev);
|
||||
mutex_unlock(&joydev_table_mutex);
|
||||
|
||||
if (!joydev)
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
error = -ENOMEM;
|
||||
goto err_put_joydev;
|
||||
}
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&client->buffer_lock);
|
||||
client->joydev = joydev;
|
||||
|
@ -288,13 +270,12 @@ static int joydev_open(struct inode *inode, struct file *file)
|
|||
file->private_data = client;
|
||||
nonseekable_open(inode, file);
|
||||
|
||||
get_device(&joydev->dev);
|
||||
return 0;
|
||||
|
||||
err_free_client:
|
||||
joydev_detach_client(joydev, client);
|
||||
kfree(client);
|
||||
err_put_joydev:
|
||||
put_device(&joydev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = {
|
|||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static int joydev_install_chrdev(struct joydev *joydev)
|
||||
{
|
||||
joydev_table[joydev->minor] = joydev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void joydev_remove_chrdev(struct joydev *joydev)
|
||||
{
|
||||
mutex_lock(&joydev_table_mutex);
|
||||
joydev_table[joydev->minor] = NULL;
|
||||
mutex_unlock(&joydev_table_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark device non-existent. This disables writes, ioctls and
|
||||
* prevents new users from opening the device. Already posted
|
||||
|
@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev)
|
|||
|
||||
joydev_mark_dead(joydev);
|
||||
joydev_hangup(joydev);
|
||||
joydev_remove_chrdev(joydev);
|
||||
|
||||
cdev_del(&joydev->cdev);
|
||||
|
||||
/* joydev is marked dead so no one else accesses joydev->open */
|
||||
if (joydev->open)
|
||||
|
@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
const struct input_device_id *id)
|
||||
{
|
||||
struct joydev *joydev;
|
||||
int i, j, t, minor;
|
||||
int i, j, t, minor, dev_no;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < JOYDEV_MINORS; minor++)
|
||||
if (!joydev_table[minor])
|
||||
break;
|
||||
|
||||
if (minor == JOYDEV_MINORS) {
|
||||
pr_err("no more free joydev devices\n");
|
||||
return -ENFILE;
|
||||
minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true);
|
||||
if (minor < 0) {
|
||||
error = minor;
|
||||
pr_err("failed to reserve new minor: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
|
||||
if (!joydev)
|
||||
return -ENOMEM;
|
||||
if (!joydev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_minor;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&joydev->client_list);
|
||||
spin_lock_init(&joydev->client_lock);
|
||||
mutex_init(&joydev->mutex);
|
||||
init_waitqueue_head(&joydev->wait);
|
||||
|
||||
dev_set_name(&joydev->dev, "js%d", minor);
|
||||
joydev->exist = true;
|
||||
joydev->minor = minor;
|
||||
|
||||
dev_no = minor;
|
||||
/* Normalize device number if it falls into legacy range */
|
||||
if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS)
|
||||
dev_no -= JOYDEV_MINOR_BASE;
|
||||
dev_set_name(&joydev->dev, "js%d", dev_no);
|
||||
|
||||
joydev->handle.dev = input_get_device(dev);
|
||||
joydev->handle.name = dev_name(&joydev->dev);
|
||||
|
@ -875,7 +847,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
}
|
||||
}
|
||||
|
||||
joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
|
||||
joydev->dev.devt = MKDEV(INPUT_MAJOR, minor);
|
||||
joydev->dev.class = &input_class;
|
||||
joydev->dev.parent = &dev->dev;
|
||||
joydev->dev.release = joydev_free;
|
||||
|
@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
if (error)
|
||||
goto err_free_joydev;
|
||||
|
||||
error = joydev_install_chrdev(joydev);
|
||||
cdev_init(&joydev->cdev, &joydev_fops);
|
||||
error = cdev_add(&joydev->cdev, joydev->dev.devt, 1);
|
||||
if (error)
|
||||
goto err_unregister_handle;
|
||||
|
||||
|
@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
input_unregister_handle(&joydev->handle);
|
||||
err_free_joydev:
|
||||
put_device(&joydev->dev);
|
||||
err_free_minor:
|
||||
input_free_minor(minor);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle)
|
|||
|
||||
device_del(&joydev->dev);
|
||||
joydev_cleanup(joydev);
|
||||
input_free_minor(MINOR(joydev->dev.devt));
|
||||
input_unregister_handle(handle);
|
||||
put_device(&joydev->dev);
|
||||
}
|
||||
|
@ -961,7 +937,7 @@ static struct input_handler joydev_handler = {
|
|||
.match = joydev_match,
|
||||
.connect = joydev_connect,
|
||||
.disconnect = joydev_disconnect,
|
||||
.fops = &joydev_fops,
|
||||
.legacy_minors = true,
|
||||
.minor = JOYDEV_MINOR_BASE,
|
||||
.name = "joydev",
|
||||
.id_table = joydev_ids,
|
||||
|
|
|
@ -431,6 +431,12 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
|
|||
goto err_unmap_base;
|
||||
}
|
||||
|
||||
error = clk_prepare(keypad->clk);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "keypad clock prepare failed\n");
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
keypad->input_dev = input_dev;
|
||||
keypad->pdev = pdev;
|
||||
keypad->row_shift = row_shift;
|
||||
|
@ -461,7 +467,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
|
|||
keypad->keycodes, input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to build keymap\n");
|
||||
goto err_put_clk;
|
||||
goto err_unprepare_clk;
|
||||
}
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
@ -503,6 +509,8 @@ err_free_irq:
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_unprepare_clk:
|
||||
clk_unprepare(keypad->clk);
|
||||
err_put_clk:
|
||||
clk_put(keypad->clk);
|
||||
samsung_keypad_dt_gpio_free(keypad);
|
||||
|
@ -531,6 +539,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
|
|||
*/
|
||||
free_irq(keypad->irq, keypad);
|
||||
|
||||
clk_unprepare(keypad->clk);
|
||||
clk_put(keypad->clk);
|
||||
samsung_keypad_dt_gpio_free(keypad);
|
||||
|
||||
|
|
|
@ -416,7 +416,7 @@ static int uinput_setup_device(struct uinput_device *udev,
|
|||
goto exit;
|
||||
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
|
||||
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)) {
|
||||
input_set_events_per_packet(dev, 60);
|
||||
}
|
||||
|
|
|
@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse)
|
|||
case ALPS_PROTO_V3:
|
||||
case ALPS_PROTO_V4:
|
||||
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_Y, 0, ALPS_V3_Y_MAX, 0, 0);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/usb/input.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/input/mt.h>
|
||||
|
||||
#define USB_VENDOR_ID_APPLE 0x05ac
|
||||
|
||||
|
@ -183,26 +184,26 @@ struct tp_finger {
|
|||
__le16 abs_y; /* absolute y coodinate */
|
||||
__le16 rel_x; /* relative x coodinate */
|
||||
__le16 rel_y; /* relative y coodinate */
|
||||
__le16 size_major; /* finger size, major axis? */
|
||||
__le16 size_minor; /* finger size, minor axis? */
|
||||
__le16 tool_major; /* tool area, major axis */
|
||||
__le16 tool_minor; /* tool area, minor axis */
|
||||
__le16 orientation; /* 16384 when point, else 15 bit angle */
|
||||
__le16 force_major; /* trackpad force, major axis? */
|
||||
__le16 force_minor; /* trackpad force, minor axis? */
|
||||
__le16 touch_major; /* touch area, major axis */
|
||||
__le16 touch_minor; /* touch area, minor axis */
|
||||
__le16 unused[3]; /* zeros */
|
||||
__le16 multi; /* one finger: varies, more fingers: constant */
|
||||
} __attribute__((packed,aligned(2)));
|
||||
|
||||
/* trackpad finger data size, empirically at least ten fingers */
|
||||
#define MAX_FINGERS 16
|
||||
#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
|
||||
|
||||
/* device-specific parameters */
|
||||
struct bcm5974_param {
|
||||
int dim; /* logical dimension */
|
||||
int fuzz; /* logical noise value */
|
||||
int devmin; /* device minimum reading */
|
||||
int devmax; /* device maximum reading */
|
||||
int snratio; /* signal-to-noise ratio */
|
||||
int min; /* device minimum reading */
|
||||
int max; /* device maximum reading */
|
||||
};
|
||||
|
||||
/* device-specific configuration */
|
||||
|
@ -219,6 +220,7 @@ struct bcm5974_config {
|
|||
struct bcm5974_param w; /* finger width limits */
|
||||
struct bcm5974_param x; /* horizontal limits */
|
||||
struct bcm5974_param y; /* vertical limits */
|
||||
struct bcm5974_param o; /* orientation limits */
|
||||
};
|
||||
|
||||
/* logical device structure */
|
||||
|
@ -234,23 +236,16 @@ struct bcm5974 {
|
|||
struct bt_data *bt_data; /* button transferred data */
|
||||
struct urb *tp_urb; /* trackpad usb request block */
|
||||
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 */
|
||||
#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 */
|
||||
|
||||
/* pressure thresholds */
|
||||
#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
|
||||
#define PRESSURE_HIGH (3 * PRESSURE_LOW)
|
||||
#define SN_ORIENT 10 /* orientation signal-to-noise ratio */
|
||||
|
||||
/* device constants */
|
||||
static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
|
@ -261,10 +256,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
0,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4824, 5342 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -172, 5820 }
|
||||
{ SN_PRESSURE, 0, 256 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4824, 5342 },
|
||||
{ SN_COORD, -172, 5820 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
|
||||
|
@ -273,10 +269,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
0,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4824, 4824 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 }
|
||||
{ SN_PRESSURE, 0, 256 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4824, 4824 },
|
||||
{ SN_COORD, -172, 4290 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI,
|
||||
|
@ -285,10 +282,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4460, 5166 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4460, 5166 },
|
||||
{ SN_COORD, -75, 6700 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
|
||||
|
@ -297,10 +295,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
{ SN_COORD, -150, 6600 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
|
||||
|
@ -309,10 +308,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4616, 5112 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4616, 5112 },
|
||||
{ SN_COORD, -142, 5234 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
|
||||
|
@ -321,10 +321,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4415, 5050 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4415, 5050 },
|
||||
{ SN_COORD, -55, 6680 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
|
||||
|
@ -333,10 +334,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
{ SN_COORD, -150, 6600 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
|
||||
|
@ -345,10 +347,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4750, 5280 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4750, 5280 },
|
||||
{ SN_COORD, -150, 6730 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
|
||||
|
@ -357,10 +360,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
{ SN_COORD, -150, 6600 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
|
||||
|
@ -369,10 +373,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
|||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
|
||||
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
|
||||
{ DIM_X, DIM_X / SN_COORD, -4750, 5280 },
|
||||
{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4750, 5280 },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
/* scale device data to logical dimensions (asserts devmin < devmax) */
|
||||
static inline int int2scale(const struct bcm5974_param *p, int x)
|
||||
static void set_abs(struct input_dev *input, unsigned int code,
|
||||
const struct bcm5974_param *p)
|
||||
{
|
||||
return x * p->dim / (p->devmax - p->devmin);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0;
|
||||
input_set_abs_params(input, code, p->min, p->max, fuzz, 0);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE,
|
||||
0, cfg->p.dim, cfg->p.fuzz, 0);
|
||||
input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
|
||||
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);
|
||||
/* for synaptics only */
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0);
|
||||
input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0);
|
||||
|
||||
/* finger touch area */
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
|
||||
cfg->w.devmin, cfg->w.devmax, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
|
||||
cfg->w.devmin, cfg->w.devmax, 0, 0);
|
||||
set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
|
||||
set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
|
||||
/* finger approach area */
|
||||
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
|
||||
cfg->w.devmin, cfg->w.devmax, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
|
||||
cfg->w.devmin, cfg->w.devmax, 0, 0);
|
||||
set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
|
||||
set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
|
||||
/* finger orientation */
|
||||
input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
|
||||
-MAX_FINGER_ORIENTATION,
|
||||
MAX_FINGER_ORIENTATION, 0, 0);
|
||||
set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
|
||||
/* finger position */
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
cfg->x.devmin, cfg->x.devmax, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
||||
cfg->y.devmin, cfg->y.devmax, 0, 0);
|
||||
set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x);
|
||||
set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y);
|
||||
|
||||
__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(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
if (cfg->caps & HAS_INTEGRATED_BUTTON)
|
||||
__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 */
|
||||
|
@ -477,24 +457,44 @@ static int report_bt_state(struct bcm5974 *dev, int size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void report_finger_data(struct input_dev *input,
|
||||
const struct bcm5974_config *cfg,
|
||||
static void report_finger_data(struct input_dev *input, int slot,
|
||||
const struct input_mt_pos *pos,
|
||||
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,
|
||||
raw2int(f->force_major) << 1);
|
||||
raw2int(f->touch_major) << 1);
|
||||
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,
|
||||
raw2int(f->size_major) << 1);
|
||||
raw2int(f->tool_major) << 1);
|
||||
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,
|
||||
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_Y,
|
||||
cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y));
|
||||
input_mt_sync(input);
|
||||
input_report_abs(input, ABS_MT_POSITION_X, pos->x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -503,9 +503,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
|||
const struct bcm5974_config *c = &dev->cfg;
|
||||
const struct tp_finger *f;
|
||||
struct input_dev *input = dev->input;
|
||||
int raw_p, raw_w, raw_x, raw_y, raw_n, i;
|
||||
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
|
||||
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
|
||||
int raw_n, i, n = 0;
|
||||
|
||||
if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
|
||||
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);
|
||||
raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
|
||||
|
||||
/* always track the first finger; when detached, start over */
|
||||
if (raw_n) {
|
||||
|
||||
/* report raw trackpad data */
|
||||
for (i = 0; i < raw_n; i++)
|
||||
report_finger_data(input, c, &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++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < raw_n; i++) {
|
||||
if (raw2int(f[i].touch_major) == 0)
|
||||
continue;
|
||||
dev->pos[n].x = raw2int(f[i].abs_x);
|
||||
dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
|
||||
dev->index[n++] = &f[i];
|
||||
}
|
||||
|
||||
/* set the integrated button if applicable */
|
||||
if (c->tp_type == TYPE2)
|
||||
ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
|
||||
input_mt_assign_slots(input, dev->slots, dev->pos, n);
|
||||
|
||||
if (dev->fingers < nmin)
|
||||
dev->fingers = nmin;
|
||||
if (dev->fingers > nmax)
|
||||
dev->fingers = nmax;
|
||||
for (i = 0; i < n; i++)
|
||||
report_finger_data(input, dev->slots[i],
|
||||
&dev->pos[i], dev->index[i]);
|
||||
|
||||
input_report_key(input, BTN_TOUCH, dev->fingers > 0);
|
||||
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_mt_sync_frame(input);
|
||||
|
||||
input_report_abs(input, ABS_PRESSURE, abs_p);
|
||||
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);
|
||||
|
||||
}
|
||||
report_synaptics_data(input, c, f, raw_n);
|
||||
|
||||
/* 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_sync(input);
|
||||
|
||||
|
@ -742,9 +693,11 @@ static int bcm5974_start_traffic(struct bcm5974 *dev)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
|
||||
if (error)
|
||||
goto err_reset_mode;
|
||||
if (dev->bt_urb) {
|
||||
error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
|
||||
if (error)
|
||||
goto err_reset_mode;
|
||||
}
|
||||
|
||||
error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
|
||||
if (error)
|
||||
|
@ -868,19 +821,23 @@ static int bcm5974_probe(struct usb_interface *iface,
|
|||
mutex_init(&dev->pm_mutex);
|
||||
|
||||
/* setup urbs */
|
||||
dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->bt_urb)
|
||||
goto err_free_devs;
|
||||
if (cfg->tp_type == TYPE1) {
|
||||
dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->bt_urb)
|
||||
goto err_free_devs;
|
||||
}
|
||||
|
||||
dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->tp_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->bt_urb->transfer_dma);
|
||||
if (!dev->bt_data)
|
||||
goto err_free_urb;
|
||||
if (!dev->bt_data)
|
||||
goto err_free_urb;
|
||||
}
|
||||
|
||||
dev->tp_data = usb_alloc_coherent(dev->udev,
|
||||
dev->cfg.tp_datalen, GFP_KERNEL,
|
||||
|
@ -888,10 +845,11 @@ static int bcm5974_probe(struct usb_interface *iface,
|
|||
if (!dev->tp_data)
|
||||
goto err_free_bt_buffer;
|
||||
|
||||
usb_fill_int_urb(dev->bt_urb, udev,
|
||||
usb_rcvintpipe(udev, cfg->bt_ep),
|
||||
dev->bt_data, dev->cfg.bt_datalen,
|
||||
bcm5974_irq_button, dev, 1);
|
||||
if (dev->bt_urb)
|
||||
usb_fill_int_urb(dev->bt_urb, udev,
|
||||
usb_rcvintpipe(udev, cfg->bt_ep),
|
||||
dev->bt_data, dev->cfg.bt_datalen,
|
||||
bcm5974_irq_button, dev, 1);
|
||||
|
||||
usb_fill_int_urb(dev->tp_urb, udev,
|
||||
usb_rcvintpipe(udev, cfg->tp_ep),
|
||||
|
@ -929,8 +887,9 @@ err_free_buffer:
|
|||
usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
|
||||
dev->tp_data, dev->tp_urb->transfer_dma);
|
||||
err_free_bt_buffer:
|
||||
usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
if (dev->bt_urb)
|
||||
usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
err_free_urb:
|
||||
usb_free_urb(dev->tp_urb);
|
||||
err_free_bt_urb:
|
||||
|
@ -951,8 +910,9 @@ static void bcm5974_disconnect(struct usb_interface *iface)
|
|||
input_unregister_device(dev->input);
|
||||
usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
|
||||
dev->tp_data, dev->tp_urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
if (dev->bt_urb)
|
||||
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->bt_urb);
|
||||
kfree(dev);
|
||||
|
|
|
@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
|||
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
|
||||
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_Y, y_min, y_max, 0, 0);
|
||||
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,
|
||||
ETP_WMAX_V2, 0, 0);
|
||||
/* 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_Y, y_min, y_max, 0, 0);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
|
||||
|
|
|
@ -971,7 +971,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_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_Y, 0, abs_y, 0, 0);
|
||||
}
|
||||
|
|
|
@ -1247,7 +1247,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);
|
||||
|
||||
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,
|
||||
ABS_MT_POSITION_Y);
|
||||
/* Image sensors can report per-contact pressure */
|
||||
|
@ -1259,7 +1259,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|||
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
|
||||
/* Non-image sensors with AGM use semi-mt */
|
||||
__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,
|
||||
ABS_MT_POSITION_Y);
|
||||
}
|
||||
|
|
|
@ -24,10 +24,8 @@
|
|||
#include <linux/random.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kernel.h>
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
#include <linux/miscdevice.h>
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
|
||||
|
@ -61,17 +59,18 @@ struct mousedev_hw_data {
|
|||
|
||||
struct mousedev {
|
||||
int open;
|
||||
int minor;
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head client_list;
|
||||
spinlock_t client_lock; /* protects client_list */
|
||||
struct mutex mutex;
|
||||
struct device dev;
|
||||
struct cdev cdev;
|
||||
bool exist;
|
||||
bool is_mixdev;
|
||||
|
||||
struct list_head mixdev_node;
|
||||
int mixdev_open;
|
||||
bool opened_by_mixdev;
|
||||
|
||||
struct mousedev_hw_data packet;
|
||||
unsigned int pkt_count;
|
||||
|
@ -114,10 +113,6 @@ struct mousedev_client {
|
|||
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
|
||||
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
|
||||
|
||||
static struct input_handler mousedev_handler;
|
||||
|
||||
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
|
||||
static DEFINE_MUTEX(mousedev_table_mutex);
|
||||
static struct mousedev *mousedev_mix;
|
||||
static LIST_HEAD(mousedev_mix_list);
|
||||
|
||||
|
@ -433,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (mousedev->minor == MOUSEDEV_MIX)
|
||||
if (mousedev->is_mixdev)
|
||||
mixdev_open_devices();
|
||||
else if (!mousedev->exist)
|
||||
retval = -ENODEV;
|
||||
|
@ -451,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
|
|||
{
|
||||
mutex_lock(&mousedev->mutex);
|
||||
|
||||
if (mousedev->minor == MOUSEDEV_MIX)
|
||||
if (mousedev->is_mixdev)
|
||||
mixdev_close_devices();
|
||||
else if (mousedev->exist && !--mousedev->open)
|
||||
input_close_device(&mousedev->handle);
|
||||
|
@ -472,11 +467,11 @@ static void mixdev_open_devices(void)
|
|||
return;
|
||||
|
||||
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
|
||||
if (!mousedev->mixdev_open) {
|
||||
if (!mousedev->opened_by_mixdev) {
|
||||
if (mousedev_open_device(mousedev))
|
||||
continue;
|
||||
|
||||
mousedev->mixdev_open = 1;
|
||||
mousedev->opened_by_mixdev = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -494,8 +489,8 @@ static void mixdev_close_devices(void)
|
|||
return;
|
||||
|
||||
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
|
||||
if (mousedev->mixdev_open) {
|
||||
mousedev->mixdev_open = 0;
|
||||
if (mousedev->opened_by_mixdev) {
|
||||
mousedev->opened_by_mixdev = false;
|
||||
mousedev_close_device(mousedev);
|
||||
}
|
||||
}
|
||||
|
@ -538,35 +533,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
|
|||
struct mousedev_client *client;
|
||||
struct mousedev *mousedev;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
if (imajor(inode) == MISC_MAJOR)
|
||||
i = MOUSEDEV_MIX;
|
||||
mousedev = mousedev_mix;
|
||||
else
|
||||
#endif
|
||||
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
|
||||
|
||||
if (i >= MOUSEDEV_MINORS)
|
||||
return -ENODEV;
|
||||
|
||||
error = mutex_lock_interruptible(&mousedev_table_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mousedev = mousedev_table[i];
|
||||
if (mousedev)
|
||||
get_device(&mousedev->dev);
|
||||
mutex_unlock(&mousedev_table_mutex);
|
||||
|
||||
if (!mousedev)
|
||||
return -ENODEV;
|
||||
mousedev = container_of(inode->i_cdev, struct mousedev, cdev);
|
||||
|
||||
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
error = -ENOMEM;
|
||||
goto err_put_mousedev;
|
||||
}
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&client->packet_lock);
|
||||
client->pos_x = xres / 2;
|
||||
|
@ -579,13 +556,14 @@ static int mousedev_open(struct inode *inode, struct file *file)
|
|||
goto err_free_client;
|
||||
|
||||
file->private_data = client;
|
||||
nonseekable_open(inode, file);
|
||||
|
||||
get_device(&mousedev->dev);
|
||||
return 0;
|
||||
|
||||
err_free_client:
|
||||
mousedev_detach_client(mousedev, client);
|
||||
kfree(client);
|
||||
err_put_mousedev:
|
||||
put_device(&mousedev->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -785,29 +763,16 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
|
|||
}
|
||||
|
||||
static const struct file_operations mousedev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = mousedev_read,
|
||||
.write = mousedev_write,
|
||||
.poll = mousedev_poll,
|
||||
.open = mousedev_open,
|
||||
.release = mousedev_release,
|
||||
.fasync = mousedev_fasync,
|
||||
.llseek = noop_llseek,
|
||||
.owner = THIS_MODULE,
|
||||
.read = mousedev_read,
|
||||
.write = mousedev_write,
|
||||
.poll = mousedev_poll,
|
||||
.open = mousedev_open,
|
||||
.release = mousedev_release,
|
||||
.fasync = mousedev_fasync,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static int mousedev_install_chrdev(struct mousedev *mousedev)
|
||||
{
|
||||
mousedev_table[mousedev->minor] = mousedev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mousedev_remove_chrdev(struct mousedev *mousedev)
|
||||
{
|
||||
mutex_lock(&mousedev_table_mutex);
|
||||
mousedev_table[mousedev->minor] = NULL;
|
||||
mutex_unlock(&mousedev_table_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark device non-existent. This disables writes, ioctls and
|
||||
* prevents new users from opening the device. Already posted
|
||||
|
@ -842,24 +807,50 @@ static void mousedev_cleanup(struct mousedev *mousedev)
|
|||
|
||||
mousedev_mark_dead(mousedev);
|
||||
mousedev_hangup(mousedev);
|
||||
mousedev_remove_chrdev(mousedev);
|
||||
|
||||
cdev_del(&mousedev->cdev);
|
||||
|
||||
/* mousedev is marked dead so no one else accesses mousedev->open */
|
||||
if (mousedev->open)
|
||||
input_close_device(handle);
|
||||
}
|
||||
|
||||
static int mousedev_reserve_minor(bool mixdev)
|
||||
{
|
||||
int minor;
|
||||
|
||||
if (mixdev) {
|
||||
minor = input_get_new_minor(MOUSEDEV_MIX, 1, false);
|
||||
if (minor < 0)
|
||||
pr_err("failed to reserve mixdev minor: %d\n", minor);
|
||||
} else {
|
||||
minor = input_get_new_minor(MOUSEDEV_MINOR_BASE,
|
||||
MOUSEDEV_MINORS, true);
|
||||
if (minor < 0)
|
||||
pr_err("failed to reserve new minor: %d\n", minor);
|
||||
}
|
||||
|
||||
return minor;
|
||||
}
|
||||
|
||||
static struct mousedev *mousedev_create(struct input_dev *dev,
|
||||
struct input_handler *handler,
|
||||
int minor)
|
||||
bool mixdev)
|
||||
{
|
||||
struct mousedev *mousedev;
|
||||
int minor;
|
||||
int error;
|
||||
|
||||
minor = mousedev_reserve_minor(mixdev);
|
||||
if (minor < 0) {
|
||||
error = minor;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
|
||||
if (!mousedev) {
|
||||
error = -ENOMEM;
|
||||
goto err_out;
|
||||
goto err_free_minor;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&mousedev->client_list);
|
||||
|
@ -867,16 +858,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|||
spin_lock_init(&mousedev->client_lock);
|
||||
mutex_init(&mousedev->mutex);
|
||||
lockdep_set_subclass(&mousedev->mutex,
|
||||
minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
|
||||
mixdev ? SINGLE_DEPTH_NESTING : 0);
|
||||
init_waitqueue_head(&mousedev->wait);
|
||||
|
||||
if (minor == MOUSEDEV_MIX)
|
||||
if (mixdev) {
|
||||
dev_set_name(&mousedev->dev, "mice");
|
||||
else
|
||||
dev_set_name(&mousedev->dev, "mouse%d", minor);
|
||||
} else {
|
||||
int dev_no = minor;
|
||||
/* Normalize device number if it falls into legacy range */
|
||||
if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
|
||||
dev_no -= MOUSEDEV_MINOR_BASE;
|
||||
dev_set_name(&mousedev->dev, "mouse%d", dev_no);
|
||||
}
|
||||
|
||||
mousedev->minor = minor;
|
||||
mousedev->exist = true;
|
||||
mousedev->is_mixdev = mixdev;
|
||||
mousedev->handle.dev = input_get_device(dev);
|
||||
mousedev->handle.name = dev_name(&mousedev->dev);
|
||||
mousedev->handle.handler = handler;
|
||||
|
@ -885,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|||
mousedev->dev.class = &input_class;
|
||||
if (dev)
|
||||
mousedev->dev.parent = &dev->dev;
|
||||
mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
|
||||
mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor);
|
||||
mousedev->dev.release = mousedev_free;
|
||||
device_initialize(&mousedev->dev);
|
||||
|
||||
if (minor != MOUSEDEV_MIX) {
|
||||
if (!mixdev) {
|
||||
error = input_register_handle(&mousedev->handle);
|
||||
if (error)
|
||||
goto err_free_mousedev;
|
||||
}
|
||||
|
||||
error = mousedev_install_chrdev(mousedev);
|
||||
cdev_init(&mousedev->cdev, &mousedev_fops);
|
||||
error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1);
|
||||
if (error)
|
||||
goto err_unregister_handle;
|
||||
|
||||
|
@ -908,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|||
err_cleanup_mousedev:
|
||||
mousedev_cleanup(mousedev);
|
||||
err_unregister_handle:
|
||||
if (minor != MOUSEDEV_MIX)
|
||||
if (!mixdev)
|
||||
input_unregister_handle(&mousedev->handle);
|
||||
err_free_mousedev:
|
||||
put_device(&mousedev->dev);
|
||||
err_free_minor:
|
||||
input_free_minor(minor);
|
||||
err_out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
@ -920,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev)
|
|||
{
|
||||
device_del(&mousedev->dev);
|
||||
mousedev_cleanup(mousedev);
|
||||
if (mousedev->minor != MOUSEDEV_MIX)
|
||||
input_free_minor(MINOR(mousedev->dev.devt));
|
||||
if (!mousedev->is_mixdev)
|
||||
input_unregister_handle(&mousedev->handle);
|
||||
put_device(&mousedev->dev);
|
||||
}
|
||||
|
@ -938,7 +938,7 @@ static int mixdev_add_device(struct mousedev *mousedev)
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
mousedev->mixdev_open = 1;
|
||||
mousedev->opened_by_mixdev = true;
|
||||
}
|
||||
|
||||
get_device(&mousedev->dev);
|
||||
|
@ -953,8 +953,8 @@ static void mixdev_remove_device(struct mousedev *mousedev)
|
|||
{
|
||||
mutex_lock(&mousedev_mix->mutex);
|
||||
|
||||
if (mousedev->mixdev_open) {
|
||||
mousedev->mixdev_open = 0;
|
||||
if (mousedev->opened_by_mixdev) {
|
||||
mousedev->opened_by_mixdev = false;
|
||||
mousedev_close_device(mousedev);
|
||||
}
|
||||
|
||||
|
@ -969,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler,
|
|||
const struct input_device_id *id)
|
||||
{
|
||||
struct mousedev *mousedev;
|
||||
int minor;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
|
||||
if (!mousedev_table[minor])
|
||||
break;
|
||||
|
||||
if (minor == MOUSEDEV_MINORS) {
|
||||
pr_err("no more free mousedev devices\n");
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
mousedev = mousedev_create(dev, handler, minor);
|
||||
mousedev = mousedev_create(dev, handler, false);
|
||||
if (IS_ERR(mousedev))
|
||||
return PTR_ERR(mousedev);
|
||||
|
||||
|
@ -1054,27 +1044,53 @@ static const struct input_device_id mousedev_ids[] = {
|
|||
MODULE_DEVICE_TABLE(input, mousedev_ids);
|
||||
|
||||
static struct input_handler mousedev_handler = {
|
||||
.event = mousedev_event,
|
||||
.connect = mousedev_connect,
|
||||
.disconnect = mousedev_disconnect,
|
||||
.fops = &mousedev_fops,
|
||||
.minor = MOUSEDEV_MINOR_BASE,
|
||||
.name = "mousedev",
|
||||
.id_table = mousedev_ids,
|
||||
.event = mousedev_event,
|
||||
.connect = mousedev_connect,
|
||||
.disconnect = mousedev_disconnect,
|
||||
.legacy_minors = true,
|
||||
.minor = MOUSEDEV_MINOR_BASE,
|
||||
.name = "mousedev",
|
||||
.id_table = mousedev_ids,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
static struct miscdevice psaux_mouse = {
|
||||
PSMOUSE_MINOR, "psaux", &mousedev_fops
|
||||
.minor = PSMOUSE_MINOR,
|
||||
.name = "psaux",
|
||||
.fops = &mousedev_fops,
|
||||
};
|
||||
static int psaux_registered;
|
||||
|
||||
static bool psaux_registered;
|
||||
|
||||
static void __init mousedev_psaux_register(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = misc_register(&psaux_mouse);
|
||||
if (error)
|
||||
pr_warn("could not register psaux device, error: %d\n",
|
||||
error);
|
||||
else
|
||||
psaux_registered = true;
|
||||
}
|
||||
|
||||
static void __exit mousedev_psaux_unregister(void)
|
||||
{
|
||||
if (psaux_registered)
|
||||
misc_deregister(&psaux_mouse);
|
||||
}
|
||||
#else
|
||||
static inline void mousedev_psaux_register(void) { }
|
||||
static inline void mousedev_psaux_unregister(void) { }
|
||||
#endif
|
||||
|
||||
static int __init mousedev_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
|
||||
mousedev_mix = mousedev_create(NULL, &mousedev_handler, true);
|
||||
if (IS_ERR(mousedev_mix))
|
||||
return PTR_ERR(mousedev_mix);
|
||||
|
||||
|
@ -1084,14 +1100,7 @@ static int __init mousedev_init(void)
|
|||
return error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
error = misc_register(&psaux_mouse);
|
||||
if (error)
|
||||
pr_warn("could not register psaux device, error: %d\n",
|
||||
error);
|
||||
else
|
||||
psaux_registered = 1;
|
||||
#endif
|
||||
mousedev_psaux_register();
|
||||
|
||||
pr_info("PS/2 mouse device common for all mice\n");
|
||||
|
||||
|
@ -1100,10 +1109,7 @@ static int __init mousedev_init(void)
|
|||
|
||||
static void __exit mousedev_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
if (psaux_registered)
|
||||
misc_deregister(&psaux_mouse);
|
||||
#endif
|
||||
mousedev_psaux_unregister();
|
||||
input_unregister_handler(&mousedev_handler);
|
||||
mousedev_destroy(mousedev_mix);
|
||||
}
|
||||
|
|
|
@ -171,6 +171,76 @@ static void wacom_close(struct input_dev *dev)
|
|||
usb_autopm_put_interface(wacom->intf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the resolution of the X or Y axis, given appropriate HID data.
|
||||
* This function is little more than hidinput_calc_abs_res stripped down.
|
||||
*/
|
||||
static int wacom_calc_hid_res(int logical_extents, int physical_extents,
|
||||
unsigned char unit, unsigned char exponent)
|
||||
{
|
||||
int prev, unit_exponent;
|
||||
|
||||
/* Check if the extents are sane */
|
||||
if (logical_extents <= 0 || physical_extents <= 0)
|
||||
return 0;
|
||||
|
||||
/* Get signed value of nybble-sized twos-compliment exponent */
|
||||
unit_exponent = exponent;
|
||||
if (unit_exponent > 7)
|
||||
unit_exponent -= 16;
|
||||
|
||||
/* Convert physical_extents to millimeters */
|
||||
if (unit == 0x11) { /* If centimeters */
|
||||
unit_exponent += 1;
|
||||
} else if (unit == 0x13) { /* If inches */
|
||||
prev = physical_extents;
|
||||
physical_extents *= 254;
|
||||
if (physical_extents < prev)
|
||||
return 0;
|
||||
unit_exponent -= 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Apply negative unit exponent */
|
||||
for (; unit_exponent < 0; unit_exponent++) {
|
||||
prev = logical_extents;
|
||||
logical_extents *= 10;
|
||||
if (logical_extents < prev)
|
||||
return 0;
|
||||
}
|
||||
/* Apply positive unit exponent */
|
||||
for (; unit_exponent > 0; unit_exponent--) {
|
||||
prev = physical_extents;
|
||||
physical_extents *= 10;
|
||||
if (physical_extents < prev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate resolution */
|
||||
return logical_extents / physical_extents;
|
||||
}
|
||||
|
||||
/*
|
||||
* The physical dimension specified by the HID descriptor is likely not in
|
||||
* the "100th of a mm" units expected by wacom_calculate_touch_res. This
|
||||
* function adjusts the value of [xy]_phy based on the unit and exponent
|
||||
* provided by the HID descriptor. If an error occurs durring conversion
|
||||
* (e.g. from the unit being left unspecified) [xy]_phy is not modified.
|
||||
*/
|
||||
static void wacom_fix_phy_from_hid(struct wacom_features *features)
|
||||
{
|
||||
int xres = wacom_calc_hid_res(features->x_max, features->x_phy,
|
||||
features->unit, features->unitExpo);
|
||||
int yres = wacom_calc_hid_res(features->y_max, features->y_phy,
|
||||
features->unit, features->unitExpo);
|
||||
|
||||
if (xres > 0 && yres > 0) {
|
||||
features->x_phy = (100 * features->x_max) / xres;
|
||||
features->y_phy = (100 * features->y_max) / yres;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Static values for max X/Y and resolution of Pen interface is stored in
|
||||
* features. This mean physical size of active area can be computed.
|
||||
|
@ -432,58 +502,54 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
|||
return result;
|
||||
}
|
||||
|
||||
static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
|
||||
static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode)
|
||||
{
|
||||
unsigned char *rep_data;
|
||||
int limit = 0, report_id = 2;
|
||||
int error = -ENOMEM;
|
||||
int error = -ENOMEM, limit = 0;
|
||||
|
||||
rep_data = kmalloc(4, GFP_KERNEL);
|
||||
rep_data = kzalloc(length, GFP_KERNEL);
|
||||
if (!rep_data)
|
||||
return error;
|
||||
|
||||
/* ask to report Wacom data */
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
/* if it is an MT Tablet PC touch */
|
||||
if (features->type > TABLETPC) {
|
||||
do {
|
||||
rep_data[0] = 3;
|
||||
rep_data[1] = 4;
|
||||
rep_data[2] = 0;
|
||||
rep_data[3] = 0;
|
||||
report_id = 3;
|
||||
error = wacom_set_report(intf,
|
||||
WAC_HID_FEATURE_REPORT,
|
||||
report_id,
|
||||
rep_data, 4, 1);
|
||||
if (error >= 0)
|
||||
error = wacom_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT,
|
||||
report_id,
|
||||
rep_data, 4, 1);
|
||||
} while ((error < 0 || rep_data[1] != 4) &&
|
||||
limit++ < WAC_MSG_RETRIES);
|
||||
}
|
||||
} else if (features->type <= BAMBOO_PT &&
|
||||
features->type != WIRELESS &&
|
||||
features->device_type == BTN_TOOL_PEN) {
|
||||
do {
|
||||
rep_data[0] = 2;
|
||||
rep_data[1] = 2;
|
||||
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2, 1);
|
||||
if (error >= 0)
|
||||
error = wacom_get_report(intf,
|
||||
WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, 2, 1);
|
||||
} while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
|
||||
}
|
||||
rep_data[0] = report_id;
|
||||
rep_data[1] = mode;
|
||||
|
||||
do {
|
||||
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, length, 1);
|
||||
if (error >= 0)
|
||||
error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
|
||||
report_id, rep_data, length, 1);
|
||||
} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
|
||||
|
||||
kfree(rep_data);
|
||||
|
||||
return error < 0 ? error : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch the tablet into its most-capable mode. Wacom tablets are
|
||||
* typically configured to power-up in a mode which sends mouse-like
|
||||
* reports to the OS. To get absolute position, pressure data, etc.
|
||||
* from the tablet, it is necessary to switch the tablet out of this
|
||||
* mode and into one which sends the full range of tablet data.
|
||||
*/
|
||||
static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
|
||||
{
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
if (features->type > TABLETPC) {
|
||||
/* MT Tablet PC touch */
|
||||
return wacom_set_device_mode(intf, 3, 4, 4);
|
||||
}
|
||||
} else if (features->device_type == BTN_TOOL_PEN) {
|
||||
if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
|
||||
return wacom_set_device_mode(intf, 2, 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
|
||||
struct wacom_features *features)
|
||||
{
|
||||
|
@ -531,6 +597,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
|
|||
error = wacom_parse_hid(intf, hid_desc, features);
|
||||
if (error)
|
||||
goto out;
|
||||
wacom_fix_phy_from_hid(features);
|
||||
|
||||
out:
|
||||
return error;
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
#define WACOM_INTUOS_RES 100
|
||||
#define WACOM_INTUOS3_RES 200
|
||||
|
||||
/* Scale factor relating reported contact size to logical contact area.
|
||||
* 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
|
||||
*/
|
||||
#define WACOM_CONTACT_AREA_SCALE 2607
|
||||
|
||||
static int wacom_penpartner_irq(struct wacom_wac *wacom)
|
||||
{
|
||||
unsigned char *data = wacom->data;
|
||||
|
@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
|||
|
||||
/* Enter report */
|
||||
if ((data[1] & 0xfc) == 0xc0) {
|
||||
if (features->type >= INTUOS5S && features->type <= INTUOS5L)
|
||||
if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = true;
|
||||
|
||||
/* serial number of the tool */
|
||||
|
@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
|||
|
||||
/* Exit report */
|
||||
if ((data[1] & 0xfe) == 0x80) {
|
||||
if (features->type >= INTUOS5S && features->type <= INTUOS5L)
|
||||
if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = false;
|
||||
|
||||
/*
|
||||
|
@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
|
|||
if (touch) {
|
||||
int x = (data[2] << 4) | (data[4] >> 4);
|
||||
int y = (data[3] << 4) | (data[4] & 0x0f);
|
||||
int w = data[6];
|
||||
int a = data[5];
|
||||
|
||||
// "a" is a scaled-down area which we assume is roughly
|
||||
// circular and which can be described as: a=(pi*r^2)/C.
|
||||
int x_res = input_abs_get_res(input, ABS_X);
|
||||
int y_res = input_abs_get_res(input, ABS_Y);
|
||||
int width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
|
||||
int height = width * y_res / x_res;
|
||||
|
||||
input_report_abs(input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, y);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, w);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1530,10 +1543,12 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
__set_bit(BTN_TOOL_TRIPLETAP, 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,
|
||||
0, 255, 0, 0);
|
||||
0, features->x_max, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
|
||||
0, features->y_max, 0, 0);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
0, features->x_max,
|
||||
|
@ -1575,7 +1590,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
case TABLETPC2FG:
|
||||
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,
|
||||
0, MT_TOOL_MAX, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
|
@ -1631,7 +1646,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
__set_bit(BTN_TOOL_FINGER, 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) {
|
||||
__set_bit(BTN_TOOL_TRIPLETAP,
|
||||
|
@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
input_set_abs_params(input_dev,
|
||||
ABS_MT_TOUCH_MAJOR,
|
||||
0, 255, 0, 0);
|
||||
0, features->x_max, 0, 0);
|
||||
input_set_abs_params(input_dev,
|
||||
ABS_MT_TOUCH_MINOR,
|
||||
0, features->y_max, 0, 0);
|
||||
}
|
||||
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
|
|
|
@ -320,10 +320,8 @@ static bool mxt_object_writable(unsigned int type)
|
|||
static void mxt_dump_message(struct device *dev,
|
||||
struct mxt_message *message)
|
||||
{
|
||||
dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
message->reportid, message->message[0], message->message[1],
|
||||
message->message[2], message->message[3], message->message[4],
|
||||
message->message[5], message->message[6]);
|
||||
dev_dbg(dev, "reportid: %u\tmessage: %*ph\n",
|
||||
message->reportid, 7, message->message);
|
||||
}
|
||||
|
||||
static int mxt_check_bootloader(struct i2c_client *client,
|
||||
|
@ -1152,7 +1150,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
|
|||
|
||||
/* For multi touch */
|
||||
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)
|
||||
goto err_free_object;
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
|
||||
|
|
|
@ -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,
|
||||
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,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
|
|
|
@ -782,7 +782,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||
0, tsdata->num_x * 64 - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
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) {
|
||||
dev_err(&client->dev, "Unable to init MT slots.\n");
|
||||
goto err_free_mem;
|
||||
|
|
|
@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client,
|
|||
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
|
||||
input_set_abs_params(input_dev,
|
||||
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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_Y, 0, ymax, 0, 0);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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,
|
||||
0, MMS114_MAX_AREA, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
|
|
|
@ -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);
|
||||
|
||||
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,
|
||||
ABS_MT_POSITION_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(pm->dev,
|
||||
|
|
|
@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001)
|
|||
case 5:
|
||||
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,
|
||||
0, touch.x, 0, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_Y,
|
||||
|
|
|
@ -414,7 +414,7 @@ struct hid_field {
|
|||
__u16 dpad; /* dpad input code */
|
||||
};
|
||||
|
||||
#define HID_MAX_FIELDS 128
|
||||
#define HID_MAX_FIELDS 256
|
||||
|
||||
struct hid_report {
|
||||
struct list_head list;
|
||||
|
@ -626,6 +626,7 @@ struct hid_usage_id {
|
|||
* @report_fixup: called before report descriptor parsing (NULL means nop)
|
||||
* @input_mapping: invoked on input registering before 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
|
||||
* @suspend: invoked on suspend (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,
|
||||
struct hid_input *hidinput, struct hid_field *field,
|
||||
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,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage);
|
||||
|
|
|
@ -1168,6 +1168,18 @@ struct ff_effect {
|
|||
#include <linux/timer.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
|
||||
* @name: name of the device
|
||||
|
@ -1203,11 +1215,7 @@ struct ff_effect {
|
|||
* software autorepeat
|
||||
* @timer: timer for software autorepeat
|
||||
* @rep: current values for autorepeat parameters (delay, rate)
|
||||
* @mt: pointer to array of struct input_mt_slot holding current values
|
||||
* 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
|
||||
* @mt: pointer to multitouch state
|
||||
* @absinfo: array of &struct input_absinfo elements holding information
|
||||
* about absolute axes (current value, min, max, flat, fuzz,
|
||||
* resolution)
|
||||
|
@ -1244,7 +1252,6 @@ struct ff_effect {
|
|||
* last user closes the device
|
||||
* @going_away: marks devices that are in a middle of unregistering and
|
||||
* 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
|
||||
* @h_list: list of input handles associated with the device. When
|
||||
* accessing the list dev->mutex must be held
|
||||
|
@ -1287,10 +1294,7 @@ struct input_dev {
|
|||
|
||||
int rep[REP_CNT];
|
||||
|
||||
struct input_mt_slot *mt;
|
||||
int mtsize;
|
||||
int slot;
|
||||
int trkid;
|
||||
struct input_mt *mt;
|
||||
|
||||
struct input_absinfo *absinfo;
|
||||
|
||||
|
@ -1312,12 +1316,14 @@ struct input_dev {
|
|||
unsigned int users;
|
||||
bool going_away;
|
||||
|
||||
bool sync;
|
||||
|
||||
struct device dev;
|
||||
|
||||
struct list_head h_list;
|
||||
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)
|
||||
|
||||
|
@ -1378,6 +1384,9 @@ struct input_handle;
|
|||
* @event: event handler. This method is being called by input core with
|
||||
* interrupts disabled and dev->event_lock spinlock held and so
|
||||
* 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
|
||||
* "filters".
|
||||
* @match: called after comparing device's id with handler's id_table
|
||||
|
@ -1387,8 +1396,8 @@ struct input_handle;
|
|||
* @start: starts handler for given handle. This function is called by
|
||||
* input core right after connect() method and also when a process
|
||||
* that "grabbed" a device releases it
|
||||
* @fops: file operations this driver implements
|
||||
* @minor: beginning of range of 32 minors for devices this driver
|
||||
* @legacy_minors: set to %true by drivers using legacy minor ranges
|
||||
* @minor: beginning of range of 32 legacy minors for devices this driver
|
||||
* can provide
|
||||
* @name: name of the handler, to be shown in /proc/bus/input/handlers
|
||||
* @id_table: pointer to a table of input_device_ids this driver can
|
||||
|
@ -1414,13 +1423,15 @@ struct input_handler {
|
|||
void *private;
|
||||
|
||||
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 (*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);
|
||||
void (*disconnect)(struct input_handle *handle);
|
||||
void (*start)(struct input_handle *handle);
|
||||
|
||||
const struct file_operations *fops;
|
||||
bool legacy_minors;
|
||||
int minor;
|
||||
const char *name;
|
||||
|
||||
|
@ -1488,6 +1499,10 @@ void input_reset_device(struct input_dev *);
|
|||
int __must_check input_register_handler(struct input_handler *);
|
||||
void input_unregister_handler(struct input_handler *);
|
||||
|
||||
int __must_check input_get_new_minor(int legacy_base, unsigned int legacy_num,
|
||||
bool allow_dynamic);
|
||||
void input_free_minor(unsigned int minor);
|
||||
|
||||
int input_handler_for_each_handle(struct input_handler *, void *data,
|
||||
int (*fn)(struct input_handle *, void *));
|
||||
|
||||
|
|
|
@ -15,12 +15,41 @@
|
|||
|
||||
#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
|
||||
* @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 {
|
||||
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,
|
||||
|
@ -35,12 +64,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
|
|||
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);
|
||||
|
||||
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)
|
||||
|
@ -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_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
|
||||
|
|
Загрузка…
Ссылка в новой задаче