Skip to content

Commit 33bbe04

Browse files
bebarinodtor
authored andcommitted
HID: google: extract Vivaldi hid feature mapping for use in hid-hammer
We need to support parsing the HID device in both the Vivaldi and the Hammer drivers so that we can properly expose the function row physmap to userspace when a hammer device uses a vivaldi keyboard layout for the function row keys. Extract the feature mapping logic from the vivaldi driver into an hid specific vivaldi library so we can use it from both HID drivers. To allow more code sharing we mandate that vivaldi data must be placed at the very beginning of the driver data attached to the HID device instance. Signed-off-by: Stephen Boyd <swboyd@chromium.org> Tested-by: Stephen Boyd <swboyd@chromium.org> # coachz, wormdingler Link: https://lore.kernel.org/r/20220228075446.466016-4-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent 45ceaf1 commit 33bbe04

5 files changed

Lines changed: 167 additions & 104 deletions

File tree

drivers/hid/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,13 @@ config HOLTEK_FF
403403
Say Y here if you have a Holtek On Line Grip based game controller
404404
and want to have force feedback support for it.
405405

406+
config HID_VIVALDI_COMMON
407+
tristate
408+
help
409+
ChromeOS Vivaldi HID parsing support library. This is a hidden
410+
option so that drivers can use common code to parse the HID
411+
descriptors for vivaldi function row keymap.
412+
406413
config HID_GOOGLE_HAMMER
407414
tristate "Google Hammer Keyboard"
408415
depends on USB_HID && LEDS_CLASS && CROS_EC
@@ -411,6 +418,7 @@ config HID_GOOGLE_HAMMER
411418

412419
config HID_VIVALDI
413420
tristate "Vivaldi Keyboard"
421+
select HID_VIVALDI_COMMON
414422
select INPUT_VIVALDIFMAP
415423
depends on HID
416424
help

drivers/hid/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ obj-$(CONFIG_HID_FT260) += hid-ft260.o
5050
obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o
5151
obj-$(CONFIG_HID_GFRM) += hid-gfrm.o
5252
obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o
53+
obj-$(CONFIG_HID_VIVALDI_COMMON) += hid-vivaldi-common.o
5354
obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o
5455
obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o
5556
obj-$(CONFIG_HID_GT683R) += hid-gt683r.o

drivers/hid/hid-vivaldi-common.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Helpers for ChromeOS HID Vivaldi keyboards
4+
*
5+
* Copyright (C) 2022 Google, Inc
6+
*/
7+
8+
#include <linux/export.h>
9+
#include <linux/hid.h>
10+
#include <linux/input/vivaldi-fmap.h>
11+
#include <linux/kernel.h>
12+
#include <linux/module.h>
13+
#include <linux/types.h>
14+
15+
#include "hid-vivaldi-common.h"
16+
17+
#define MIN_FN_ROW_KEY 1
18+
#define MAX_FN_ROW_KEY VIVALDI_MAX_FUNCTION_ROW_KEYS
19+
#define HID_VD_FN_ROW_PHYSMAP 0x00000001
20+
#define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP)
21+
22+
/**
23+
* vivaldi_feature_mapping - Fill out vivaldi keymap data exposed via HID
24+
* @hdev: HID device to parse
25+
* @field: HID field to parse
26+
* @usage: HID usage to parse
27+
*
28+
* Note: this function assumes that driver data attached to @hdev contains an
29+
* instance of &struct vivaldi_data at the very beginning.
30+
*/
31+
void vivaldi_feature_mapping(struct hid_device *hdev,
32+
struct hid_field *field, struct hid_usage *usage)
33+
{
34+
struct vivaldi_data *data = hid_get_drvdata(hdev);
35+
struct hid_report *report = field->report;
36+
u8 *report_data, *buf;
37+
u32 report_len;
38+
unsigned int fn_key;
39+
int ret;
40+
41+
if (field->logical != HID_USAGE_FN_ROW_PHYSMAP ||
42+
(usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL)
43+
return;
44+
45+
fn_key = usage->hid & HID_USAGE;
46+
if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY)
47+
return;
48+
49+
if (fn_key > data->num_function_row_keys)
50+
data->num_function_row_keys = fn_key;
51+
52+
report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL);
53+
if (!report_data)
54+
return;
55+
56+
report_len = hid_report_len(report);
57+
if (!report->id) {
58+
/*
59+
* hid_hw_raw_request() will stuff report ID (which will be 0)
60+
* into the first byte of the buffer even for unnumbered
61+
* reports, so we need to account for this to avoid getting
62+
* -EOVERFLOW in return.
63+
* Note that hid_alloc_report_buf() adds 7 bytes to the size
64+
* so we can safely say that we have space for an extra byte.
65+
*/
66+
report_len++;
67+
}
68+
69+
ret = hid_hw_raw_request(hdev, report->id, report_data,
70+
report_len, HID_FEATURE_REPORT,
71+
HID_REQ_GET_REPORT);
72+
if (ret < 0) {
73+
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
74+
field->report->id);
75+
goto out;
76+
}
77+
78+
if (!report->id) {
79+
/*
80+
* Undo the damage from hid_hw_raw_request() for unnumbered
81+
* reports.
82+
*/
83+
report_data++;
84+
report_len--;
85+
}
86+
87+
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data,
88+
report_len, 0);
89+
if (ret) {
90+
dev_warn(&hdev->dev, "failed to report feature %d\n",
91+
field->report->id);
92+
goto out;
93+
}
94+
95+
data->function_row_physmap[fn_key - MIN_FN_ROW_KEY] =
96+
field->value[usage->usage_index];
97+
98+
out:
99+
kfree(buf);
100+
}
101+
EXPORT_SYMBOL_GPL(vivaldi_feature_mapping);
102+
103+
static ssize_t function_row_physmap_show(struct device *dev,
104+
struct device_attribute *attr,
105+
char *buf)
106+
{
107+
struct hid_device *hdev = to_hid_device(dev);
108+
struct vivaldi_data *data = hid_get_drvdata(hdev);
109+
110+
return vivaldi_function_row_physmap_show(data, buf);
111+
}
112+
113+
static DEVICE_ATTR_RO(function_row_physmap);
114+
static struct attribute *vivaldi_sysfs_attrs[] = {
115+
&dev_attr_function_row_physmap.attr,
116+
NULL
117+
};
118+
119+
static const struct attribute_group vivaldi_attribute_group = {
120+
.attrs = vivaldi_sysfs_attrs,
121+
};
122+
123+
/**
124+
* vivaldi_input_configured - Complete initialization of device using vivaldi map
125+
* @hdev: HID device to which vivaldi attributes should be attached
126+
* @hidinput: HID input device (unused)
127+
*/
128+
int vivaldi_input_configured(struct hid_device *hdev,
129+
struct hid_input *hidinput)
130+
{
131+
struct vivaldi_data *data = hid_get_drvdata(hdev);
132+
133+
if (!data->num_function_row_keys)
134+
return 0;
135+
136+
return devm_device_add_group(&hdev->dev, &vivaldi_attribute_group);
137+
}
138+
EXPORT_SYMBOL_GPL(vivaldi_input_configured);
139+
140+
MODULE_LICENSE("GPL");

drivers/hid/hid-vivaldi-common.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _HID_VIVALDI_COMMON_H
3+
#define _HID_VIVALDI_COMMON_H
4+
5+
struct hid_device;
6+
struct hid_field;
7+
struct hid_input;
8+
struct hid_usage;
9+
10+
void vivaldi_feature_mapping(struct hid_device *hdev,
11+
struct hid_field *field, struct hid_usage *usage);
12+
13+
int vivaldi_input_configured(struct hid_device *hdev,
14+
struct hid_input *hidinput);
15+
16+
#endif /* _HID_VIVALDI_COMMON_H */

drivers/hid/hid-vivaldi.c

Lines changed: 2 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,8 @@
1111
#include <linux/input/vivaldi-fmap.h>
1212
#include <linux/kernel.h>
1313
#include <linux/module.h>
14-
#include <linux/sysfs.h>
1514

16-
#define MIN_FN_ROW_KEY 1
17-
#define MAX_FN_ROW_KEY VIVALDI_MAX_FUNCTION_ROW_KEYS
18-
#define HID_VD_FN_ROW_PHYSMAP 0x00000001
19-
#define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP)
20-
21-
static ssize_t function_row_physmap_show(struct device *dev,
22-
struct device_attribute *attr,
23-
char *buf)
24-
{
25-
struct hid_device *hdev = to_hid_device(dev);
26-
struct vivaldi_data *drvdata = hid_get_drvdata(hdev);
27-
28-
return vivaldi_function_row_physmap_show(drvdata, buf);
29-
}
30-
31-
static DEVICE_ATTR_RO(function_row_physmap);
32-
static struct attribute *sysfs_attrs[] = {
33-
&dev_attr_function_row_physmap.attr,
34-
NULL
35-
};
36-
37-
static const struct attribute_group input_attribute_group = {
38-
.attrs = sysfs_attrs
39-
};
15+
#include "hid-vivaldi-common.h"
4016

4117
static int vivaldi_probe(struct hid_device *hdev,
4218
const struct hid_device_id *id)
@@ -57,86 +33,8 @@ static int vivaldi_probe(struct hid_device *hdev,
5733
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
5834
}
5935

60-
static void vivaldi_feature_mapping(struct hid_device *hdev,
61-
struct hid_field *field,
62-
struct hid_usage *usage)
63-
{
64-
struct vivaldi_data *drvdata = hid_get_drvdata(hdev);
65-
struct hid_report *report = field->report;
66-
int fn_key;
67-
int ret;
68-
u32 report_len;
69-
u8 *report_data, *buf;
70-
71-
if (field->logical != HID_USAGE_FN_ROW_PHYSMAP ||
72-
(usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL)
73-
return;
74-
75-
fn_key = usage->hid & HID_USAGE;
76-
if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY)
77-
return;
78-
if (fn_key > drvdata->num_function_row_keys)
79-
drvdata->num_function_row_keys = fn_key;
80-
81-
report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL);
82-
if (!report_data)
83-
return;
84-
85-
report_len = hid_report_len(report);
86-
if (!report->id) {
87-
/*
88-
* hid_hw_raw_request() will stuff report ID (which will be 0)
89-
* into the first byte of the buffer even for unnumbered
90-
* reports, so we need to account for this to avoid getting
91-
* -EOVERFLOW in return.
92-
* Note that hid_alloc_report_buf() adds 7 bytes to the size
93-
* so we can safely say that we have space for an extra byte.
94-
*/
95-
report_len++;
96-
}
97-
98-
ret = hid_hw_raw_request(hdev, report->id, report_data,
99-
report_len, HID_FEATURE_REPORT,
100-
HID_REQ_GET_REPORT);
101-
if (ret < 0) {
102-
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
103-
field->report->id);
104-
goto out;
105-
}
106-
107-
if (!report->id) {
108-
/*
109-
* Undo the damage from hid_hw_raw_request() for unnumbered
110-
* reports.
111-
*/
112-
report_data++;
113-
report_len--;
114-
}
115-
116-
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data,
117-
report_len, 0);
118-
if (ret) {
119-
dev_warn(&hdev->dev, "failed to report feature %d\n",
120-
field->report->id);
121-
goto out;
122-
}
123-
124-
drvdata->function_row_physmap[fn_key - MIN_FN_ROW_KEY] =
125-
field->value[usage->usage_index];
126-
127-
out:
128-
kfree(buf);
129-
}
130-
131-
static int vivaldi_input_configured(struct hid_device *hdev,
132-
struct hid_input *hidinput)
133-
{
134-
return devm_device_add_group(&hdev->dev, &input_attribute_group);
135-
}
136-
13736
static const struct hid_device_id vivaldi_table[] = {
138-
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID,
139-
HID_ANY_ID) },
37+
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID, HID_ANY_ID) },
14038
{ }
14139
};
14240

0 commit comments

Comments
 (0)