1 // SPDX-License-Identifier: GPL-2.0
3 * HID support for Vivaldi Keyboard
5 * Copyright 2020 Google LLC.
6 * Author: Sean O'Brien <seobrien@chromium.org>
10 #include <linux/module.h>
12 #define MIN_FN_ROW_KEY 1
13 #define MAX_FN_ROW_KEY 24
14 #define HID_VD_FN_ROW_PHYSMAP 0x00000001
15 #define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP)
17 static struct hid_driver hid_vivaldi
;
20 u32 function_row_physmap
[MAX_FN_ROW_KEY
- MIN_FN_ROW_KEY
+ 1];
21 int max_function_row_key
;
24 static ssize_t
function_row_physmap_show(struct device
*dev
,
25 struct device_attribute
*attr
,
28 struct hid_device
*hdev
= to_hid_device(dev
);
29 struct vivaldi_data
*drvdata
= hid_get_drvdata(hdev
);
33 if (!drvdata
->max_function_row_key
)
36 for (i
= 0; i
< drvdata
->max_function_row_key
; i
++)
37 size
+= sprintf(buf
+ size
, "%02X ",
38 drvdata
->function_row_physmap
[i
]);
39 size
+= sprintf(buf
+ size
, "\n");
43 DEVICE_ATTR_RO(function_row_physmap
);
44 static struct attribute
*sysfs_attrs
[] = {
45 &dev_attr_function_row_physmap
.attr
,
49 static const struct attribute_group input_attribute_group
= {
53 static int vivaldi_probe(struct hid_device
*hdev
,
54 const struct hid_device_id
*id
)
56 struct vivaldi_data
*drvdata
;
59 drvdata
= devm_kzalloc(&hdev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
60 hid_set_drvdata(hdev
, drvdata
);
62 ret
= hid_parse(hdev
);
66 return hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
69 static void vivaldi_feature_mapping(struct hid_device
*hdev
,
70 struct hid_field
*field
,
71 struct hid_usage
*usage
)
73 struct vivaldi_data
*drvdata
= hid_get_drvdata(hdev
);
79 if (field
->logical
!= HID_USAGE_FN_ROW_PHYSMAP
||
80 (usage
->hid
& HID_USAGE_PAGE
) != HID_UP_ORDINAL
)
83 fn_key
= (usage
->hid
& HID_USAGE
);
84 if (fn_key
< MIN_FN_ROW_KEY
|| fn_key
> MAX_FN_ROW_KEY
)
86 if (fn_key
> drvdata
->max_function_row_key
)
87 drvdata
->max_function_row_key
= fn_key
;
89 buf
= hid_alloc_report_buf(field
->report
, GFP_KERNEL
);
93 report_len
= hid_report_len(field
->report
);
94 ret
= hid_hw_raw_request(hdev
, field
->report
->id
, buf
,
95 report_len
, HID_FEATURE_REPORT
,
98 dev_warn(&hdev
->dev
, "failed to fetch feature %d\n",
103 ret
= hid_report_raw_event(hdev
, HID_FEATURE_REPORT
, buf
,
106 dev_warn(&hdev
->dev
, "failed to report feature %d\n",
111 drvdata
->function_row_physmap
[fn_key
- MIN_FN_ROW_KEY
] =
112 field
->value
[usage
->usage_index
];
118 static int vivaldi_input_configured(struct hid_device
*hdev
,
119 struct hid_input
*hidinput
)
121 return sysfs_create_group(&hdev
->dev
.kobj
, &input_attribute_group
);
124 static const struct hid_device_id vivaldi_table
[] = {
125 { HID_DEVICE(HID_BUS_ANY
, HID_GROUP_VIVALDI
, HID_ANY_ID
,
130 MODULE_DEVICE_TABLE(hid
, vivaldi_table
);
132 static struct hid_driver hid_vivaldi
= {
133 .name
= "hid-vivaldi",
134 .id_table
= vivaldi_table
,
135 .probe
= vivaldi_probe
,
136 .feature_mapping
= vivaldi_feature_mapping
,
137 .input_configured
= vivaldi_input_configured
,
140 module_hid_driver(hid_vivaldi
);
142 MODULE_AUTHOR("Sean O'Brien");
143 MODULE_DESCRIPTION("HID vivaldi driver");
144 MODULE_LICENSE("GPL");