Merge branch 'for-5.18/core' into for-linus
- rework of generic input handling which ultimately makes the processing of tablet events more generic and reliable (Benjamin Tissoires)
This commit is contained in:
commit
a2ff005927
|
@ -137,7 +137,11 @@ A few EV_KEY codes have special meanings:
|
|||
code should be set to a value of 1. When the tool is no longer interacting
|
||||
with the input device, the BTN_TOOL_<name> code should be reset to 0. All
|
||||
trackpads, tablets, and touchscreens should use at least one BTN_TOOL_<name>
|
||||
code when events are generated.
|
||||
code when events are generated. Likewise all trackpads, tablets, and
|
||||
touchscreens should export only one BTN_TOOL_<name> at a time. To not break
|
||||
existing userspace, it is recommended to not switch tool in one EV_SYN frame
|
||||
but first emitting the old BTN_TOOL_<name> at 0, then emit one SYN_REPORT
|
||||
and then set the new BTN_TOOL_<name> at 1.
|
||||
|
||||
* BTN_TOUCH:
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
|
|||
report_enum->report_id_hash[id] = report;
|
||||
|
||||
list_add_tail(&report->list, &report_enum->report_list);
|
||||
INIT_LIST_HEAD(&report->field_entry_list);
|
||||
|
||||
return report;
|
||||
}
|
||||
|
@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
|||
|
||||
field = kzalloc((sizeof(struct hid_field) +
|
||||
usages * sizeof(struct hid_usage) +
|
||||
usages * sizeof(unsigned)), GFP_KERNEL);
|
||||
3 * usages * sizeof(unsigned int)), GFP_KERNEL);
|
||||
if (!field)
|
||||
return NULL;
|
||||
|
||||
|
@ -109,6 +110,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
|||
report->field[field->index] = field;
|
||||
field->usage = (struct hid_usage *)(field + 1);
|
||||
field->value = (s32 *)(field->usage + usages);
|
||||
field->new_value = (s32 *)(field->value + usages);
|
||||
field->usages_priorities = (s32 *)(field->new_value + usages);
|
||||
field->report = report;
|
||||
|
||||
return field;
|
||||
|
@ -656,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
|
|||
{
|
||||
unsigned n;
|
||||
|
||||
kfree(report->field_entries);
|
||||
|
||||
for (n = 0; n < report->maxfield; n++)
|
||||
kfree(report->field[n]);
|
||||
kfree(report);
|
||||
|
@ -1525,25 +1530,41 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
|
|||
}
|
||||
|
||||
/*
|
||||
* Analyse a received field, and fetch the data from it. The field
|
||||
* content is stored for next report processing (we do differential
|
||||
* reporting to the layer).
|
||||
* Checks if the given value is valid within this field
|
||||
*/
|
||||
static inline int hid_array_value_is_valid(struct hid_field *field,
|
||||
__s32 value)
|
||||
{
|
||||
__s32 min = field->logical_minimum;
|
||||
|
||||
static void hid_input_field(struct hid_device *hid, struct hid_field *field,
|
||||
__u8 *data, int interrupt)
|
||||
/*
|
||||
* Value needs to be between logical min and max, and
|
||||
* (value - min) is used as an index in the usage array.
|
||||
* This array is of size field->maxusage
|
||||
*/
|
||||
return value >= min &&
|
||||
value <= field->logical_maximum &&
|
||||
value - min < field->maxusage;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the field from the data. The field content is stored for next
|
||||
* report processing (we do differential reporting to the layer).
|
||||
*/
|
||||
static void hid_input_fetch_field(struct hid_device *hid,
|
||||
struct hid_field *field,
|
||||
__u8 *data)
|
||||
{
|
||||
unsigned n;
|
||||
unsigned count = field->report_count;
|
||||
unsigned offset = field->report_offset;
|
||||
unsigned size = field->report_size;
|
||||
__s32 min = field->logical_minimum;
|
||||
__s32 max = field->logical_maximum;
|
||||
__s32 *value;
|
||||
|
||||
value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC);
|
||||
if (!value)
|
||||
return;
|
||||
value = field->new_value;
|
||||
memset(value, 0, count * sizeof(__s32));
|
||||
field->ignored = false;
|
||||
|
||||
for (n = 0; n < count; n++) {
|
||||
|
||||
|
@ -1554,35 +1575,228 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
|
|||
|
||||
/* Ignore report if ErrorRollOver */
|
||||
if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
|
||||
value[n] >= min && value[n] <= max &&
|
||||
value[n] - min < field->maxusage &&
|
||||
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
|
||||
goto exit;
|
||||
hid_array_value_is_valid(field, value[n]) &&
|
||||
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) {
|
||||
field->ignored = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a received variable field.
|
||||
*/
|
||||
|
||||
static void hid_input_var_field(struct hid_device *hid,
|
||||
struct hid_field *field,
|
||||
int interrupt)
|
||||
{
|
||||
unsigned int count = field->report_count;
|
||||
__s32 *value = field->new_value;
|
||||
unsigned int n;
|
||||
|
||||
for (n = 0; n < count; n++)
|
||||
hid_process_event(hid,
|
||||
field,
|
||||
&field->usage[n],
|
||||
value[n],
|
||||
interrupt);
|
||||
|
||||
memcpy(field->value, value, count * sizeof(__s32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a received array field. The field content is stored for
|
||||
* next report processing (we do differential reporting to the layer).
|
||||
*/
|
||||
|
||||
static void hid_input_array_field(struct hid_device *hid,
|
||||
struct hid_field *field,
|
||||
int interrupt)
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned int count = field->report_count;
|
||||
__s32 min = field->logical_minimum;
|
||||
__s32 *value;
|
||||
|
||||
value = field->new_value;
|
||||
|
||||
/* ErrorRollOver */
|
||||
if (field->ignored)
|
||||
return;
|
||||
|
||||
for (n = 0; n < count; n++) {
|
||||
if (hid_array_value_is_valid(field, field->value[n]) &&
|
||||
search(value, field->value[n], count))
|
||||
hid_process_event(hid,
|
||||
field,
|
||||
&field->usage[field->value[n] - min],
|
||||
0,
|
||||
interrupt);
|
||||
|
||||
if (HID_MAIN_ITEM_VARIABLE & field->flags) {
|
||||
hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field->value[n] >= min && field->value[n] <= max
|
||||
&& field->value[n] - min < field->maxusage
|
||||
&& field->usage[field->value[n] - min].hid
|
||||
&& search(value, field->value[n], count))
|
||||
hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
|
||||
|
||||
if (value[n] >= min && value[n] <= max
|
||||
&& value[n] - min < field->maxusage
|
||||
&& field->usage[value[n] - min].hid
|
||||
&& search(field->value, value[n], count))
|
||||
hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
|
||||
if (hid_array_value_is_valid(field, value[n]) &&
|
||||
search(field->value, value[n], count))
|
||||
hid_process_event(hid,
|
||||
field,
|
||||
&field->usage[value[n] - min],
|
||||
1,
|
||||
interrupt);
|
||||
}
|
||||
|
||||
memcpy(field->value, value, count * sizeof(__s32));
|
||||
exit:
|
||||
kfree(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse a received report, and fetch the data from it. The field
|
||||
* content is stored for next report processing (we do differential
|
||||
* reporting to the layer).
|
||||
*/
|
||||
static void hid_process_report(struct hid_device *hid,
|
||||
struct hid_report *report,
|
||||
__u8 *data,
|
||||
int interrupt)
|
||||
{
|
||||
unsigned int a;
|
||||
struct hid_field_entry *entry;
|
||||
struct hid_field *field;
|
||||
|
||||
/* first retrieve all incoming values in data */
|
||||
for (a = 0; a < report->maxfield; a++)
|
||||
hid_input_fetch_field(hid, field = report->field[a], data);
|
||||
|
||||
if (!list_empty(&report->field_entry_list)) {
|
||||
/* INPUT_REPORT, we have a priority list of fields */
|
||||
list_for_each_entry(entry,
|
||||
&report->field_entry_list,
|
||||
list) {
|
||||
field = entry->field;
|
||||
|
||||
if (field->flags & HID_MAIN_ITEM_VARIABLE)
|
||||
hid_process_event(hid,
|
||||
field,
|
||||
&field->usage[entry->index],
|
||||
field->new_value[entry->index],
|
||||
interrupt);
|
||||
else
|
||||
hid_input_array_field(hid, field, interrupt);
|
||||
}
|
||||
|
||||
/* we need to do the memcpy at the end for var items */
|
||||
for (a = 0; a < report->maxfield; a++) {
|
||||
field = report->field[a];
|
||||
|
||||
if (field->flags & HID_MAIN_ITEM_VARIABLE)
|
||||
memcpy(field->value, field->new_value,
|
||||
field->report_count * sizeof(__s32));
|
||||
}
|
||||
} else {
|
||||
/* FEATURE_REPORT, regular processing */
|
||||
for (a = 0; a < report->maxfield; a++) {
|
||||
field = report->field[a];
|
||||
|
||||
if (field->flags & HID_MAIN_ITEM_VARIABLE)
|
||||
hid_input_var_field(hid, field, interrupt);
|
||||
else
|
||||
hid_input_array_field(hid, field, interrupt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a given usage_index in a field in the list
|
||||
* of processed usages in the report.
|
||||
*
|
||||
* The elements of lower priority score are processed
|
||||
* first.
|
||||
*/
|
||||
static void __hid_insert_field_entry(struct hid_device *hid,
|
||||
struct hid_report *report,
|
||||
struct hid_field_entry *entry,
|
||||
struct hid_field *field,
|
||||
unsigned int usage_index)
|
||||
{
|
||||
struct hid_field_entry *next;
|
||||
|
||||
entry->field = field;
|
||||
entry->index = usage_index;
|
||||
entry->priority = field->usages_priorities[usage_index];
|
||||
|
||||
/* insert the element at the correct position */
|
||||
list_for_each_entry(next,
|
||||
&report->field_entry_list,
|
||||
list) {
|
||||
/*
|
||||
* the priority of our element is strictly higher
|
||||
* than the next one, insert it before
|
||||
*/
|
||||
if (entry->priority > next->priority) {
|
||||
list_add_tail(&entry->list, &next->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* lowest priority score: insert at the end */
|
||||
list_add_tail(&entry->list, &report->field_entry_list);
|
||||
}
|
||||
|
||||
static void hid_report_process_ordering(struct hid_device *hid,
|
||||
struct hid_report *report)
|
||||
{
|
||||
struct hid_field *field;
|
||||
struct hid_field_entry *entries;
|
||||
unsigned int a, u, usages;
|
||||
unsigned int count = 0;
|
||||
|
||||
/* count the number of individual fields in the report */
|
||||
for (a = 0; a < report->maxfield; a++) {
|
||||
field = report->field[a];
|
||||
|
||||
if (field->flags & HID_MAIN_ITEM_VARIABLE)
|
||||
count += field->report_count;
|
||||
else
|
||||
count++;
|
||||
}
|
||||
|
||||
/* allocate the memory to process the fields */
|
||||
entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
|
||||
if (!entries)
|
||||
return;
|
||||
|
||||
report->field_entries = entries;
|
||||
|
||||
/*
|
||||
* walk through all fields in the report and
|
||||
* store them by priority order in report->field_entry_list
|
||||
*
|
||||
* - Var elements are individualized (field + usage_index)
|
||||
* - Arrays are taken as one, we can not chose an order for them
|
||||
*/
|
||||
usages = 0;
|
||||
for (a = 0; a < report->maxfield; a++) {
|
||||
field = report->field[a];
|
||||
|
||||
if (field->flags & HID_MAIN_ITEM_VARIABLE) {
|
||||
for (u = 0; u < field->report_count; u++) {
|
||||
__hid_insert_field_entry(hid, report,
|
||||
&entries[usages],
|
||||
field, u);
|
||||
usages++;
|
||||
}
|
||||
} else {
|
||||
__hid_insert_field_entry(hid, report, &entries[usages],
|
||||
field, 0);
|
||||
usages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_process_ordering(struct hid_device *hid)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];
|
||||
|
||||
list_for_each_entry(report, &report_enum->report_list, list)
|
||||
hid_report_process_ordering(hid, report);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1746,7 +1960,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
|||
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||||
struct hid_report *report;
|
||||
struct hid_driver *hdrv;
|
||||
unsigned int a;
|
||||
u32 rsize, csize = size;
|
||||
u8 *cdata = data;
|
||||
int ret = 0;
|
||||
|
@ -1782,8 +1995,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
|||
}
|
||||
|
||||
if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
|
||||
for (a = 0; a < report->maxfield; a++)
|
||||
hid_input_field(hid, report->field[a], cdata, interrupt);
|
||||
hid_process_report(hid, report, cdata, interrupt);
|
||||
hdrv = hid->driver;
|
||||
if (hdrv && hdrv->report)
|
||||
hdrv->report(hid, report);
|
||||
|
@ -1970,6 +2182,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
hid_process_ordering(hdev);
|
||||
|
||||
if ((hdev->claimed & HID_CLAIMED_INPUT) &&
|
||||
(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
|
||||
hdev->ff_init(hdev);
|
||||
|
|
|
@ -48,6 +48,51 @@ static const struct {
|
|||
__s32 y;
|
||||
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
struct usage_priority {
|
||||
__u32 usage; /* the HID usage associated */
|
||||
bool global; /* we assume all usages to be slotted,
|
||||
* unless global
|
||||
*/
|
||||
unsigned int slot_overwrite; /* for globals: allows to set the usage
|
||||
* before or after the slots
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* hid-input will convert this list into priorities:
|
||||
* the first element will have the highest priority
|
||||
* (the length of the following array) and the last
|
||||
* element the lowest (1).
|
||||
*
|
||||
* hid-input will then shift the priority by 8 bits to leave some space
|
||||
* in case drivers want to interleave other fields.
|
||||
*
|
||||
* To accommodate slotted devices, the slot priority is
|
||||
* defined in the next 8 bits (defined by 0xff - slot).
|
||||
*
|
||||
* If drivers want to add fields before those, hid-input will
|
||||
* leave out the first 8 bits of the priority value.
|
||||
*
|
||||
* This still leaves us 65535 individual priority values.
|
||||
*/
|
||||
static const struct usage_priority hidinput_usages_priorities[] = {
|
||||
{ /* Eraser (eraser touching) must always come before tipswitch */
|
||||
.usage = HID_DG_ERASER,
|
||||
},
|
||||
{ /* Invert must always come before In Range */
|
||||
.usage = HID_DG_INVERT,
|
||||
},
|
||||
{ /* Is the tip of the tool touching? */
|
||||
.usage = HID_DG_TIPSWITCH,
|
||||
},
|
||||
{ /* Tip Pressure might emulate tip switch */
|
||||
.usage = HID_DG_TIPPRESSURE,
|
||||
},
|
||||
{ /* In Range needs to come after the other tool states */
|
||||
.usage = HID_DG_INRANGE,
|
||||
},
|
||||
};
|
||||
|
||||
#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
|
||||
#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
|
||||
#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
|
||||
|
@ -586,11 +631,13 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f
|
|||
}
|
||||
|
||||
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
|
||||
struct hid_usage *usage)
|
||||
struct hid_usage *usage, unsigned int usage_index)
|
||||
{
|
||||
struct input_dev *input = hidinput->input;
|
||||
struct hid_device *device = input_get_drvdata(input);
|
||||
const struct usage_priority *usage_priority = NULL;
|
||||
int max = 0, code;
|
||||
unsigned int i = 0;
|
||||
unsigned long *bit = NULL;
|
||||
|
||||
field->hidinput = hidinput;
|
||||
|
@ -608,6 +655,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
goto ignore;
|
||||
}
|
||||
|
||||
/* assign a priority based on the static list declared here */
|
||||
for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
|
||||
if (usage->hid == hidinput_usages_priorities[i].usage) {
|
||||
usage_priority = &hidinput_usages_priorities[i];
|
||||
|
||||
field->usages_priorities[usage_index] =
|
||||
(ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For slotted devices, we need to also add the slot index
|
||||
* in the priority.
|
||||
*/
|
||||
if (usage_priority && usage_priority->global)
|
||||
field->usages_priorities[usage_index] |=
|
||||
usage_priority->slot_overwrite;
|
||||
else
|
||||
field->usages_priorities[usage_index] |=
|
||||
(0xff - field->slot_idx) << 16;
|
||||
|
||||
if (device->driver->input_mapping) {
|
||||
int ret = device->driver->input_mapping(device, hidinput, field,
|
||||
usage, &bit, &max);
|
||||
|
@ -828,10 +897,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
break;
|
||||
|
||||
case 0x32: /* InRange */
|
||||
switch (field->physical & 0xff) {
|
||||
case 0x21: map_key(BTN_TOOL_MOUSE); break;
|
||||
case 0x22: map_key(BTN_TOOL_FINGER); break;
|
||||
default: map_key(BTN_TOOL_PEN); break;
|
||||
switch (field->physical) {
|
||||
case HID_DG_PUCK:
|
||||
map_key(BTN_TOOL_MOUSE);
|
||||
break;
|
||||
case HID_DG_FINGER:
|
||||
map_key(BTN_TOOL_FINGER);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If the physical is not given,
|
||||
* rely on the application.
|
||||
*/
|
||||
if (!field->physical) {
|
||||
switch (field->application) {
|
||||
case HID_DG_TOUCHSCREEN:
|
||||
case HID_DG_TOUCHPAD:
|
||||
map_key_clear(BTN_TOOL_FINGER);
|
||||
break;
|
||||
default:
|
||||
map_key_clear(BTN_TOOL_PEN);
|
||||
}
|
||||
} else {
|
||||
map_key(BTN_TOOL_PEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1315,9 +1405,38 @@ static void hidinput_handle_scroll(struct hid_usage *usage,
|
|||
input_event(input, EV_REL, usage->code, hi_res);
|
||||
}
|
||||
|
||||
static void hid_report_release_tool(struct hid_report *report, struct input_dev *input,
|
||||
unsigned int tool)
|
||||
{
|
||||
/* if the given tool is not currently reported, ignore */
|
||||
if (!test_bit(tool, input->key))
|
||||
return;
|
||||
|
||||
/*
|
||||
* if the given tool was previously set, release it,
|
||||
* release any TOUCH and send an EV_SYN
|
||||
*/
|
||||
input_event(input, EV_KEY, BTN_TOUCH, 0);
|
||||
input_event(input, EV_KEY, tool, 0);
|
||||
input_event(input, EV_SYN, SYN_REPORT, 0);
|
||||
|
||||
report->tool = 0;
|
||||
}
|
||||
|
||||
static void hid_report_set_tool(struct hid_report *report, struct input_dev *input,
|
||||
unsigned int new_tool)
|
||||
{
|
||||
if (report->tool != new_tool)
|
||||
hid_report_release_tool(report, input, report->tool);
|
||||
|
||||
input_event(input, EV_KEY, new_tool, 1);
|
||||
report->tool = new_tool;
|
||||
}
|
||||
|
||||
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct input_dev *input;
|
||||
struct hid_report *report = field->report;
|
||||
unsigned *quirks = &hid->quirks;
|
||||
|
||||
if (!usage->type)
|
||||
|
@ -1333,12 +1452,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|||
|
||||
input = field->hidinput->input;
|
||||
|
||||
if (usage->type == EV_ABS &&
|
||||
(((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
|
||||
((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) {
|
||||
value = field->logical_maximum - value;
|
||||
}
|
||||
|
||||
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
|
||||
int hat_dir = usage->hat_dir;
|
||||
if (!hat_dir)
|
||||
|
@ -1349,61 +1462,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|||
return;
|
||||
}
|
||||
|
||||
if (usage->hid == HID_DG_INVERT) {
|
||||
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->hid == HID_DG_INRANGE) {
|
||||
if (value) {
|
||||
input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
|
||||
return;
|
||||
}
|
||||
input_event(input, usage->type, usage->code, 0);
|
||||
input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
|
||||
int a = field->logical_minimum;
|
||||
int b = field->logical_maximum;
|
||||
input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
|
||||
}
|
||||
|
||||
if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
|
||||
dbg_hid("Maximum Effects - %d\n",value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->hid == (HID_UP_PID | 0x7fUL)) {
|
||||
dbg_hid("PID Pool Report\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
|
||||
return;
|
||||
|
||||
if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
|
||||
usage->code == REL_HWHEEL_HI_RES)) {
|
||||
hidinput_handle_scroll(usage, input, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
|
||||
(usage->code == ABS_VOLUME)) {
|
||||
int count = abs(value);
|
||||
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
input_event(input, EV_KEY, direction, 1);
|
||||
input_sync(input);
|
||||
input_event(input, EV_KEY, direction, 0);
|
||||
input_sync(input);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore out-of-range values as per HID specification,
|
||||
* section 5.10 and 6.2.25, when NULL state bit is present.
|
||||
|
@ -1416,7 +1474,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|||
* don't specify logical min and max.
|
||||
*/
|
||||
if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
|
||||
(field->logical_minimum < field->logical_maximum)) {
|
||||
field->logical_minimum < field->logical_maximum) {
|
||||
if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
|
||||
(value < field->logical_minimum ||
|
||||
value > field->logical_maximum)) {
|
||||
|
@ -1428,6 +1486,123 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|||
field->logical_maximum);
|
||||
}
|
||||
|
||||
switch (usage->hid) {
|
||||
case HID_DG_ERASER:
|
||||
report->tool_active |= !!value;
|
||||
|
||||
/*
|
||||
* if eraser is set, we must enforce BTN_TOOL_RUBBER
|
||||
* to accommodate for devices not following the spec.
|
||||
*/
|
||||
if (value)
|
||||
hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
|
||||
else if (report->tool != BTN_TOOL_RUBBER)
|
||||
/* value is off, tool is not rubber, ignore */
|
||||
return;
|
||||
|
||||
/* let hid-input set BTN_TOUCH */
|
||||
break;
|
||||
|
||||
case HID_DG_INVERT:
|
||||
report->tool_active |= !!value;
|
||||
|
||||
/*
|
||||
* If invert is set, we store BTN_TOOL_RUBBER.
|
||||
*/
|
||||
if (value)
|
||||
hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
|
||||
else if (!report->tool_active)
|
||||
/* tool_active not set means Invert and Eraser are not set */
|
||||
hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
|
||||
|
||||
/* no further processing */
|
||||
return;
|
||||
|
||||
case HID_DG_INRANGE:
|
||||
report->tool_active |= !!value;
|
||||
|
||||
if (report->tool_active) {
|
||||
/*
|
||||
* if tool is not set but is marked as active,
|
||||
* assume ours
|
||||
*/
|
||||
if (!report->tool)
|
||||
hid_report_set_tool(report, input, usage->code);
|
||||
} else {
|
||||
hid_report_release_tool(report, input, usage->code);
|
||||
}
|
||||
|
||||
/* reset tool_active for the next event */
|
||||
report->tool_active = false;
|
||||
|
||||
/* no further processing */
|
||||
return;
|
||||
|
||||
case HID_DG_TIPSWITCH:
|
||||
report->tool_active |= !!value;
|
||||
|
||||
/* if tool is set to RUBBER we should ignore the current value */
|
||||
if (report->tool == BTN_TOOL_RUBBER)
|
||||
return;
|
||||
|
||||
break;
|
||||
|
||||
case HID_DG_TIPPRESSURE:
|
||||
if (*quirks & HID_QUIRK_NOTOUCH) {
|
||||
int a = field->logical_minimum;
|
||||
int b = field->logical_maximum;
|
||||
|
||||
if (value > a + ((b - a) >> 3)) {
|
||||
input_event(input, EV_KEY, BTN_TOUCH, 1);
|
||||
report->tool_active = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */
|
||||
dbg_hid("Maximum Effects - %d\n",value);
|
||||
return;
|
||||
|
||||
case HID_UP_PID | 0x7fUL:
|
||||
dbg_hid("PID Pool Report\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (usage->type) {
|
||||
case EV_KEY:
|
||||
if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */
|
||||
return;
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
if (usage->code == REL_WHEEL_HI_RES ||
|
||||
usage->code == REL_HWHEEL_HI_RES) {
|
||||
hidinput_handle_scroll(usage, input, value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
|
||||
usage->code == ABS_VOLUME) {
|
||||
int count = abs(value);
|
||||
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
input_event(input, EV_KEY, direction, 1);
|
||||
input_sync(input);
|
||||
input_event(input, EV_KEY, direction, 0);
|
||||
input_sync(input);
|
||||
}
|
||||
return;
|
||||
|
||||
} else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
|
||||
((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))
|
||||
value = field->logical_maximum - value;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore reports for absolute data if the data didn't change. This is
|
||||
* not only an optimization but also fixes 'dead' key reports. Some
|
||||
|
@ -1930,12 +2105,63 @@ static struct hid_input *hidinput_match_application(struct hid_report *report)
|
|||
static inline void hidinput_configure_usages(struct hid_input *hidinput,
|
||||
struct hid_report *report)
|
||||
{
|
||||
int i, j;
|
||||
int i, j, k;
|
||||
int first_field_index = 0;
|
||||
int slot_collection_index = -1;
|
||||
int prev_collection_index = -1;
|
||||
unsigned int slot_idx = 0;
|
||||
struct hid_field *field;
|
||||
|
||||
/*
|
||||
* First tag all the fields that are part of a slot,
|
||||
* a slot needs to have one Contact ID in the collection
|
||||
*/
|
||||
for (i = 0; i < report->maxfield; i++) {
|
||||
field = report->field[i];
|
||||
|
||||
/* ignore fields without usage */
|
||||
if (field->maxusage < 1)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* janitoring when collection_index changes
|
||||
*/
|
||||
if (prev_collection_index != field->usage->collection_index) {
|
||||
prev_collection_index = field->usage->collection_index;
|
||||
first_field_index = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we already found a Contact ID in the collection,
|
||||
* tag and continue to the next.
|
||||
*/
|
||||
if (slot_collection_index == field->usage->collection_index) {
|
||||
field->slot_idx = slot_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if the current field has Contact ID */
|
||||
for (j = 0; j < field->maxusage; j++) {
|
||||
if (field->usage[j].hid == HID_DG_CONTACTID) {
|
||||
slot_collection_index = field->usage->collection_index;
|
||||
slot_idx++;
|
||||
|
||||
/*
|
||||
* mark all previous fields and this one in the
|
||||
* current collection to be slotted.
|
||||
*/
|
||||
for (k = first_field_index; k <= i; k++)
|
||||
report->field[k]->slot_idx = slot_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < report->maxfield; i++)
|
||||
for (j = 0; j < report->field[i]->maxusage; j++)
|
||||
hidinput_configure_usage(hidinput, report->field[i],
|
||||
report->field[i]->usage + j);
|
||||
report->field[i]->usage + j,
|
||||
j);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -347,7 +347,7 @@ struct hid_item {
|
|||
*/
|
||||
#define MAX_USBHID_BOOT_QUIRKS 4
|
||||
|
||||
#define HID_QUIRK_INVERT BIT(0)
|
||||
/* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
|
||||
#define HID_QUIRK_NOTOUCH BIT(1)
|
||||
#define HID_QUIRK_IGNORE BIT(2)
|
||||
#define HID_QUIRK_NOGET BIT(3)
|
||||
|
@ -476,31 +476,50 @@ struct hid_field {
|
|||
unsigned report_count; /* number of this field in the report */
|
||||
unsigned report_type; /* (input,output,feature) */
|
||||
__s32 *value; /* last known value(s) */
|
||||
__s32 *new_value; /* newly read value(s) */
|
||||
__s32 *usages_priorities; /* priority of each usage when reading the report
|
||||
* bits 8-16 are reserved for hid-input usage
|
||||
*/
|
||||
__s32 logical_minimum;
|
||||
__s32 logical_maximum;
|
||||
__s32 physical_minimum;
|
||||
__s32 physical_maximum;
|
||||
__s32 unit_exponent;
|
||||
unsigned unit;
|
||||
bool ignored; /* this field is ignored in this event */
|
||||
struct hid_report *report; /* associated report */
|
||||
unsigned index; /* index into report->field[] */
|
||||
/* hidinput data */
|
||||
struct hid_input *hidinput; /* associated input structure */
|
||||
__u16 dpad; /* dpad input code */
|
||||
unsigned int slot_idx; /* slot index in a report */
|
||||
};
|
||||
|
||||
#define HID_MAX_FIELDS 256
|
||||
|
||||
struct hid_field_entry {
|
||||
struct list_head list;
|
||||
struct hid_field *field;
|
||||
unsigned int index;
|
||||
__s32 priority;
|
||||
};
|
||||
|
||||
struct hid_report {
|
||||
struct list_head list;
|
||||
struct list_head hidinput_list;
|
||||
struct list_head field_entry_list; /* ordered list of input fields */
|
||||
unsigned int id; /* id of this report */
|
||||
unsigned int type; /* report type */
|
||||
unsigned int application; /* application usage for this report */
|
||||
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
|
||||
struct hid_field_entry *field_entries; /* allocated memory of input field_entry */
|
||||
unsigned maxfield; /* maximum valid field index */
|
||||
unsigned size; /* size of the report (bits) */
|
||||
struct hid_device *device; /* associated device */
|
||||
|
||||
/* tool related state */
|
||||
bool tool_active; /* whether the current tool is active */
|
||||
unsigned int tool; /* BTN_TOOL_* */
|
||||
};
|
||||
|
||||
#define HID_MAX_IDS 256
|
||||
|
|
Loading…
Reference in New Issue