Loading drivers/hid/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -397,6 +397,15 @@ config HID_GOOGLE_HAMMER help Say Y here if you have a Google Hammer device. config HID_VIVALDI tristate "Vivaldi Keyboard" depends on HID help Say Y here if you want to enable support for Vivaldi keyboards. Vivaldi keyboards use a vendor-specific (Google) HID usage to report how the keys in the top row are physically ordered. config HID_GT683R tristate "MSI GT68xR LED support" depends on LEDS_CLASS && USB_HID Loading drivers/hid/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o Loading drivers/hid/hid-core.c +7 −0 Original line number Diff line number Diff line Loading @@ -814,6 +814,13 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; if ((parser->global.usage_page << 16) == HID_UP_GOOGLEVENDOR) for (i = 0; i < parser->local.usage_index; i++) if (parser->local.usage[i] == (HID_UP_GOOGLEVENDOR | 0x0001)) parser->device->group = HID_GROUP_VIVALDI; } static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) Loading drivers/hid/hid-vivaldi.c 0 → 100644 +144 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * HID support for Vivaldi Keyboard * * Copyright 2020 Google LLC. * Author: Sean O'Brien <seobrien@chromium.org> */ #include <linux/hid.h> #include <linux/module.h> #define MIN_FN_ROW_KEY 1 #define MAX_FN_ROW_KEY 24 #define HID_VD_FN_ROW_PHYSMAP 0x00000001 #define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) static struct hid_driver hid_vivaldi; struct vivaldi_data { u32 function_row_physmap[MAX_FN_ROW_KEY - MIN_FN_ROW_KEY + 1]; int max_function_row_key; }; static ssize_t function_row_physmap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct vivaldi_data *drvdata = hid_get_drvdata(hdev); ssize_t size = 0; int i; if (!drvdata->max_function_row_key) return 0; for (i = 0; i < drvdata->max_function_row_key; i++) size += sprintf(buf + size, "%02X ", drvdata->function_row_physmap[i]); size += sprintf(buf + size, "\n"); return size; } DEVICE_ATTR_RO(function_row_physmap); static struct attribute *sysfs_attrs[] = { &dev_attr_function_row_physmap.attr, NULL }; static const struct attribute_group input_attribute_group = { .attrs = sysfs_attrs }; static int vivaldi_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct vivaldi_data *drvdata; int ret; drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); hid_set_drvdata(hdev, drvdata); ret = hid_parse(hdev); if (ret) return ret; return hid_hw_start(hdev, HID_CONNECT_DEFAULT); } static void vivaldi_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { struct vivaldi_data *drvdata = hid_get_drvdata(hdev); int fn_key; int ret; u32 report_len; u8 *buf; if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) return; fn_key = (usage->hid & HID_USAGE); if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY) return; if (fn_key > drvdata->max_function_row_key) drvdata->max_function_row_key = fn_key; buf = hid_alloc_report_buf(field->report, GFP_KERNEL); if (!buf) return; report_len = hid_report_len(field->report); ret = hid_hw_raw_request(hdev, field->report->id, buf, report_len, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) { dev_warn(&hdev->dev, "failed to fetch feature %d\n", field->report->id); goto out; } ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, report_len, 0); if (ret) { dev_warn(&hdev->dev, "failed to report feature %d\n", field->report->id); goto out; } drvdata->function_row_physmap[fn_key - MIN_FN_ROW_KEY] = field->value[usage->usage_index]; out: kfree(buf); } static int vivaldi_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { return sysfs_create_group(&hdev->dev.kobj, &input_attribute_group); } static const struct hid_device_id vivaldi_table[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID, HID_ANY_ID) }, { } }; MODULE_DEVICE_TABLE(hid, vivaldi_table); static struct hid_driver hid_vivaldi = { .name = "hid-vivaldi", .id_table = vivaldi_table, .probe = vivaldi_probe, .feature_mapping = vivaldi_feature_mapping, .input_configured = vivaldi_input_configured, }; module_hid_driver(hid_vivaldi); MODULE_AUTHOR("Sean O'Brien"); MODULE_DESCRIPTION("HID vivaldi driver"); MODULE_LICENSE("GPL"); include/linux/hid.h +2 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ struct hid_item { #define HID_UP_LNVENDOR 0xffa00000 #define HID_UP_SENSOR 0x00200000 #define HID_UP_ASUSVENDOR 0xff310000 #define HID_UP_GOOGLEVENDOR 0xffd10000 #define HID_USAGE 0x0000ffff Loading Loading @@ -371,6 +372,7 @@ struct hid_item { #define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102 #define HID_GROUP_STEAM 0x0103 #define HID_GROUP_LOGITECH_27MHZ_DEVICE 0x0104 #define HID_GROUP_VIVALDI 0x0105 /* * HID protocol status Loading Loading
drivers/hid/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -397,6 +397,15 @@ config HID_GOOGLE_HAMMER help Say Y here if you have a Google Hammer device. config HID_VIVALDI tristate "Vivaldi Keyboard" depends on HID help Say Y here if you want to enable support for Vivaldi keyboards. Vivaldi keyboards use a vendor-specific (Google) HID usage to report how the keys in the top row are physically ordered. config HID_GT683R tristate "MSI GT68xR LED support" depends on LEDS_CLASS && USB_HID Loading
drivers/hid/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o Loading
drivers/hid/hid-core.c +7 −0 Original line number Diff line number Diff line Loading @@ -814,6 +814,13 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; if ((parser->global.usage_page << 16) == HID_UP_GOOGLEVENDOR) for (i = 0; i < parser->local.usage_index; i++) if (parser->local.usage[i] == (HID_UP_GOOGLEVENDOR | 0x0001)) parser->device->group = HID_GROUP_VIVALDI; } static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) Loading
drivers/hid/hid-vivaldi.c 0 → 100644 +144 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * HID support for Vivaldi Keyboard * * Copyright 2020 Google LLC. * Author: Sean O'Brien <seobrien@chromium.org> */ #include <linux/hid.h> #include <linux/module.h> #define MIN_FN_ROW_KEY 1 #define MAX_FN_ROW_KEY 24 #define HID_VD_FN_ROW_PHYSMAP 0x00000001 #define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) static struct hid_driver hid_vivaldi; struct vivaldi_data { u32 function_row_physmap[MAX_FN_ROW_KEY - MIN_FN_ROW_KEY + 1]; int max_function_row_key; }; static ssize_t function_row_physmap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct vivaldi_data *drvdata = hid_get_drvdata(hdev); ssize_t size = 0; int i; if (!drvdata->max_function_row_key) return 0; for (i = 0; i < drvdata->max_function_row_key; i++) size += sprintf(buf + size, "%02X ", drvdata->function_row_physmap[i]); size += sprintf(buf + size, "\n"); return size; } DEVICE_ATTR_RO(function_row_physmap); static struct attribute *sysfs_attrs[] = { &dev_attr_function_row_physmap.attr, NULL }; static const struct attribute_group input_attribute_group = { .attrs = sysfs_attrs }; static int vivaldi_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct vivaldi_data *drvdata; int ret; drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); hid_set_drvdata(hdev, drvdata); ret = hid_parse(hdev); if (ret) return ret; return hid_hw_start(hdev, HID_CONNECT_DEFAULT); } static void vivaldi_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { struct vivaldi_data *drvdata = hid_get_drvdata(hdev); int fn_key; int ret; u32 report_len; u8 *buf; if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) return; fn_key = (usage->hid & HID_USAGE); if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY) return; if (fn_key > drvdata->max_function_row_key) drvdata->max_function_row_key = fn_key; buf = hid_alloc_report_buf(field->report, GFP_KERNEL); if (!buf) return; report_len = hid_report_len(field->report); ret = hid_hw_raw_request(hdev, field->report->id, buf, report_len, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) { dev_warn(&hdev->dev, "failed to fetch feature %d\n", field->report->id); goto out; } ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, report_len, 0); if (ret) { dev_warn(&hdev->dev, "failed to report feature %d\n", field->report->id); goto out; } drvdata->function_row_physmap[fn_key - MIN_FN_ROW_KEY] = field->value[usage->usage_index]; out: kfree(buf); } static int vivaldi_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { return sysfs_create_group(&hdev->dev.kobj, &input_attribute_group); } static const struct hid_device_id vivaldi_table[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID, HID_ANY_ID) }, { } }; MODULE_DEVICE_TABLE(hid, vivaldi_table); static struct hid_driver hid_vivaldi = { .name = "hid-vivaldi", .id_table = vivaldi_table, .probe = vivaldi_probe, .feature_mapping = vivaldi_feature_mapping, .input_configured = vivaldi_input_configured, }; module_hid_driver(hid_vivaldi); MODULE_AUTHOR("Sean O'Brien"); MODULE_DESCRIPTION("HID vivaldi driver"); MODULE_LICENSE("GPL");
include/linux/hid.h +2 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ struct hid_item { #define HID_UP_LNVENDOR 0xffa00000 #define HID_UP_SENSOR 0x00200000 #define HID_UP_ASUSVENDOR 0xff310000 #define HID_UP_GOOGLEVENDOR 0xffd10000 #define HID_USAGE 0x0000ffff Loading Loading @@ -371,6 +372,7 @@ struct hid_item { #define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102 #define HID_GROUP_STEAM 0x0103 #define HID_GROUP_LOGITECH_27MHZ_DEVICE 0x0104 #define HID_GROUP_VIVALDI 0x0105 /* * HID protocol status Loading