cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hid-vivaldi-common.c (3722B)


      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 */
     31void 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
     98out:
     99	kfree(buf);
    100}
    101EXPORT_SYMBOL_GPL(vivaldi_feature_mapping);
    102
    103static 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
    113static DEVICE_ATTR_RO(function_row_physmap);
    114static struct attribute *vivaldi_sysfs_attrs[] = {
    115	&dev_attr_function_row_physmap.attr,
    116	NULL
    117};
    118
    119static 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 */
    128int 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}
    138EXPORT_SYMBOL_GPL(vivaldi_input_configured);
    139
    140MODULE_LICENSE("GPL");