Skip to content

Commit

Permalink
HID: core: add helper for finding a field with a certain usage
Browse files Browse the repository at this point in the history
This helper will allow HID drivers to easily determine if they should
bind to a hid_device by checking for the prescence of a certain field
when its ID is not enough, which can be the case on USB devices with
multiple interfaces and/or configurations.

Convert google-hammer driver to use it, and remove now superfluous
hammer_has_usage().

[jkosina@suse.com: expand changelog with the information about
 google-hammer being added as user of this API ]
Signed-off-by: Kerem Karabay <kekrby@gmail.com>
Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
  • Loading branch information
Kerem Karabay authored and Jiri Kosina committed Aug 2, 2024
1 parent 6b5faec commit 6edb8cd
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 25 deletions.
25 changes: 25 additions & 0 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,31 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
}
EXPORT_SYMBOL_GPL(hid_set_field);

struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
unsigned int application, unsigned int usage)
{
struct list_head *report_list = &hdev->report_enum[report_type].report_list;
struct hid_report *report;
int i, j;

list_for_each_entry(report, report_list, list) {
if (report->application != application)
continue;

for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i];

for (j = 0; j < field->maxusage; j++) {
if (field->usage[j].hid == usage)
return field;
}
}
}

return NULL;
}
EXPORT_SYMBOL_GPL(hid_find_field);

static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
const u8 *data)
{
Expand Down
27 changes: 2 additions & 25 deletions drivers/hid/hid-google-hammer.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,38 +418,15 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
return 0;
}

static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
unsigned application, unsigned usage)
{
struct hid_report_enum *re = &hdev->report_enum[report_type];
struct hid_report *report;
int i, j;

list_for_each_entry(report, &re->report_list, list) {
if (report->application != application)
continue;

for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i];

for (j = 0; j < field->maxusage; j++)
if (field->usage[j].hid == usage)
return true;
}
}

return false;
}

static bool hammer_has_folded_event(struct hid_device *hdev)
{
return hammer_has_usage(hdev, HID_INPUT_REPORT,
return !!hid_find_field(hdev, HID_INPUT_REPORT,
HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
}

static bool hammer_has_backlight_control(struct hid_device *hdev)
{
return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
return !!hid_find_field(hdev, HID_OUTPUT_REPORT,
HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
}

Expand Down
2 changes: 2 additions & 0 deletions include/linux/hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,8 @@ extern void hidinput_report_event(struct hid_device *hid, struct hid_report *rep
extern int hidinput_connect(struct hid_device *hid, unsigned int force);
extern void hidinput_disconnect(struct hid_device *);

struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
unsigned int application, unsigned int usage);
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt);
Expand Down

0 comments on commit 6edb8cd

Please sign in to comment.