HID: generic: create one input report per application type

It is not a good idea to try to fit all types of applications in the
same input report. There are a lot of devices that are needing
the quirk HID_MULTI_INPUT but this quirk doesn't match the actual HID
description as it is based on the report ID.

Given that most devices with MULTI_INPUT I can think of split nicely
the devices inputs into application, it is a good thing to split the
devices by default based on this assumption.

Also make hid-multitouch following this rule, to not have to deal
with too many input created.

While we are at it, fix some checkpatch complaints about converting
'unsigned' to 'unsigned int'.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
Benjamin Tissoires 2018-04-24 10:04:33 +02:00 committed by Jiri Kosina
parent e1b63c0148
commit f07b3c1da9
6 changed files with 56 additions and 13 deletions

View File

@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
* Register a new report for a device. * Register a new report for a device.
*/ */
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) struct hid_report *hid_register_report(struct hid_device *device,
unsigned int type, unsigned int id,
unsigned int application)
{ {
struct hid_report_enum *report_enum = device->report_enum + type; struct hid_report_enum *report_enum = device->report_enum + type;
struct hid_report *report; struct hid_report *report;
@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
report->type = type; report->type = type;
report->size = 0; report->size = 0;
report->device = device; report->device = device;
report->application = application;
report_enum->report_id_hash[id] = report; report_enum->report_id_hash[id] = report;
list_add_tail(&report->list, &report_enum->report_list); list_add_tail(&report->list, &report_enum->report_list);
@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{ {
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
unsigned usages; unsigned int usages;
unsigned offset; unsigned int offset;
unsigned i; unsigned int i;
unsigned int application;
report = hid_register_report(parser->device, report_type, parser->global.report_id); application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
report = hid_register_report(parser->device, report_type,
parser->global.report_id, application);
if (!report) { if (!report) {
hid_err(parser->device, "hid_register_report failed\n"); hid_err(parser->device, "hid_register_report failed\n");
return -1; return -1;
@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); field->application = application;
for (i = 0; i < usages; i++) { for (i = 0; i < usages; i++) {
unsigned j = i; unsigned j = i;

View File

@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev,
return true; return true;
} }
static int hid_generic_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
ret = hid_parse(hdev);
if (ret)
return ret;
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
static const struct hid_device_id hid_table[] = { static const struct hid_device_id hid_table[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
{ } { }
@ -66,6 +80,7 @@ static struct hid_driver hid_generic = {
.name = "hid-generic", .name = "hid-generic",
.id_table = hid_table, .id_table = hid_table,
.match = hid_generic_match, .match = hid_generic_match,
.probe = hid_generic_probe,
}; };
module_hid_driver(hid_generic); module_hid_driver(hid_generic);

View File

@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
* those reports reach gfrm_raw_event() from hid_input_report(). * those reports reach gfrm_raw_event() from hid_input_report().
*/ */
if (!hid_register_report(hdev, HID_INPUT_REPORT, if (!hid_register_report(hdev, HID_INPUT_REPORT,
GFRM100_SEARCH_KEY_REPORT_ID)) { GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }

View File

@ -1610,6 +1610,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
return NULL; return NULL;
} }
static struct hid_input *hidinput_match_application(struct hid_report *report)
{
struct hid_device *hid = report->device;
struct hid_input *hidinput;
list_for_each_entry(hidinput, &hid->inputs, list) {
if (hidinput->report &&
hidinput->report->application == report->application)
return hidinput;
}
return NULL;
}
static inline void hidinput_configure_usages(struct hid_input *hidinput, static inline void hidinput_configure_usages(struct hid_input *hidinput,
struct hid_report *report) struct hid_report *report)
{ {
@ -1670,6 +1684,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
*/ */
if (hid->quirks & HID_QUIRK_MULTI_INPUT) if (hid->quirks & HID_QUIRK_MULTI_INPUT)
hidinput = hidinput_match(report); hidinput = hidinput_match(report);
else if (hid->maxapplication > 1 &&
(hid->quirks & HID_QUIRK_INPUT_PER_APP))
hidinput = hidinput_match_application(report);
if (!hidinput) { if (!hidinput) {
hidinput = hidinput_allocate(hid); hidinput = hidinput_allocate(hid);

View File

@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev,
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
MOUSE_REPORT_ID); MOUSE_REPORT_ID, 0);
else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
TRACKPAD_REPORT_ID); TRACKPAD_REPORT_ID, 0);
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
DOUBLE_REPORT_ID); DOUBLE_REPORT_ID, 0);
} }
if (!report) { if (!report) {

View File

@ -341,6 +341,7 @@ struct hid_item {
/* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */ /* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */
/* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ /* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
#define HID_QUIRK_ALWAYS_POLL BIT(10) #define HID_QUIRK_ALWAYS_POLL BIT(10)
#define HID_QUIRK_INPUT_PER_APP BIT(11)
#define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16) #define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16)
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17) #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17)
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
@ -465,8 +466,9 @@ struct hid_field {
struct hid_report { struct hid_report {
struct list_head list; struct list_head list;
struct list_head hidinput_list; struct list_head hidinput_list;
unsigned id; /* id of this report */ unsigned int id; /* id of this report */
unsigned type; /* report type */ 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 *field[HID_MAX_FIELDS]; /* fields of the report */
unsigned maxfield; /* maximum valid field index */ unsigned maxfield; /* maximum valid field index */
unsigned size; /* size of the report (bits) */ unsigned size; /* size of the report (bits) */
@ -861,7 +863,9 @@ void hid_output_report(struct hid_report *report, __u8 *data);
void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype); void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void); struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); struct hid_report *hid_register_report(struct hid_device *device,
unsigned int type, unsigned int id,
unsigned int application);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
struct hid_report *hid_validate_values(struct hid_device *hid, struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int type, unsigned int id, unsigned int type, unsigned int id,