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-google-hammer.c (16084B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  HID driver for Google Hammer device.
      4 *
      5 *  Copyright (c) 2017 Google Inc.
      6 *  Author: Wei-Ning Huang <wnhuang@google.com>
      7 */
      8
      9/*
     10 * This program is free software; you can redistribute it and/or modify it
     11 * under the terms of the GNU General Public License as published by the Free
     12 * Software Foundation; either version 2 of the License, or (at your option)
     13 * any later version.
     14 */
     15
     16#include <linux/acpi.h>
     17#include <linux/hid.h>
     18#include <linux/input/vivaldi-fmap.h>
     19#include <linux/leds.h>
     20#include <linux/module.h>
     21#include <linux/of.h>
     22#include <linux/platform_data/cros_ec_commands.h>
     23#include <linux/platform_data/cros_ec_proto.h>
     24#include <linux/platform_device.h>
     25#include <linux/pm_wakeup.h>
     26#include <asm/unaligned.h>
     27
     28#include "hid-ids.h"
     29#include "hid-vivaldi-common.h"
     30
     31/*
     32 * C(hrome)B(ase)A(ttached)S(witch) - switch exported by Chrome EC and reporting
     33 * state of the "Whiskers" base - attached or detached. Whiskers USB device also
     34 * reports position of the keyboard - folded or not. Combining base state and
     35 * position allows us to generate proper "Tablet mode" events.
     36 */
     37struct cbas_ec {
     38	struct device *dev;	/* The platform device (EC) */
     39	struct input_dev *input;
     40	bool base_present;
     41	bool base_folded;
     42	struct notifier_block notifier;
     43};
     44
     45static struct cbas_ec cbas_ec;
     46static DEFINE_SPINLOCK(cbas_ec_lock);
     47static DEFINE_MUTEX(cbas_ec_reglock);
     48
     49static bool cbas_parse_base_state(const void *data)
     50{
     51	u32 switches = get_unaligned_le32(data);
     52
     53	return !!(switches & BIT(EC_MKBP_BASE_ATTACHED));
     54}
     55
     56static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state,
     57				  bool *state)
     58{
     59	struct ec_params_mkbp_info *params;
     60	struct cros_ec_command *msg;
     61	int ret;
     62
     63	msg = kzalloc(struct_size(msg, data, max(sizeof(u32), sizeof(*params))),
     64		      GFP_KERNEL);
     65	if (!msg)
     66		return -ENOMEM;
     67
     68	msg->command = EC_CMD_MKBP_INFO;
     69	msg->version = 1;
     70	msg->outsize = sizeof(*params);
     71	msg->insize = sizeof(u32);
     72	params = (struct ec_params_mkbp_info *)msg->data;
     73	params->info_type = get_state ?
     74		EC_MKBP_INFO_CURRENT : EC_MKBP_INFO_SUPPORTED;
     75	params->event_type = EC_MKBP_EVENT_SWITCH;
     76
     77	ret = cros_ec_cmd_xfer_status(ec_dev, msg);
     78	if (ret >= 0) {
     79		if (ret != sizeof(u32)) {
     80			dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n",
     81				 ret, sizeof(u32));
     82			ret = -EPROTO;
     83		} else {
     84			*state = cbas_parse_base_state(msg->data);
     85			ret = 0;
     86		}
     87	}
     88
     89	kfree(msg);
     90
     91	return ret;
     92}
     93
     94static int cbas_ec_notify(struct notifier_block *nb,
     95			      unsigned long queued_during_suspend,
     96			      void *_notify)
     97{
     98	struct cros_ec_device *ec = _notify;
     99	unsigned long flags;
    100	bool base_present;
    101
    102	if (ec->event_data.event_type == EC_MKBP_EVENT_SWITCH) {
    103		base_present = cbas_parse_base_state(
    104					&ec->event_data.data.switches);
    105		dev_dbg(cbas_ec.dev,
    106			"%s: base: %d\n", __func__, base_present);
    107
    108		if (device_may_wakeup(cbas_ec.dev) ||
    109		    !queued_during_suspend) {
    110
    111			pm_wakeup_event(cbas_ec.dev, 0);
    112
    113			spin_lock_irqsave(&cbas_ec_lock, flags);
    114
    115			/*
    116			 * While input layer dedupes the events, we do not want
    117			 * to disrupt the state reported by the base by
    118			 * overriding it with state reported by the LID. Only
    119			 * report changes, as we assume that on attach the base
    120			 * is not folded.
    121			 */
    122			if (base_present != cbas_ec.base_present) {
    123				input_report_switch(cbas_ec.input,
    124						    SW_TABLET_MODE,
    125						    !base_present);
    126				input_sync(cbas_ec.input);
    127				cbas_ec.base_present = base_present;
    128			}
    129
    130			spin_unlock_irqrestore(&cbas_ec_lock, flags);
    131		}
    132	}
    133
    134	return NOTIFY_OK;
    135}
    136
    137static __maybe_unused int cbas_ec_resume(struct device *dev)
    138{
    139	struct cros_ec_device *ec = dev_get_drvdata(dev->parent);
    140	bool base_present;
    141	int error;
    142
    143	error = cbas_ec_query_base(ec, true, &base_present);
    144	if (error) {
    145		dev_warn(dev, "failed to fetch base state on resume: %d\n",
    146			 error);
    147	} else {
    148		spin_lock_irq(&cbas_ec_lock);
    149
    150		cbas_ec.base_present = base_present;
    151
    152		/*
    153		 * Only report if base is disconnected. If base is connected,
    154		 * it will resend its state on resume, and we'll update it
    155		 * in hammer_event().
    156		 */
    157		if (!cbas_ec.base_present) {
    158			input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
    159			input_sync(cbas_ec.input);
    160		}
    161
    162		spin_unlock_irq(&cbas_ec_lock);
    163	}
    164
    165	return 0;
    166}
    167
    168static SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume);
    169
    170static void cbas_ec_set_input(struct input_dev *input)
    171{
    172	/* Take the lock so hammer_event() does not race with us here */
    173	spin_lock_irq(&cbas_ec_lock);
    174	cbas_ec.input = input;
    175	spin_unlock_irq(&cbas_ec_lock);
    176}
    177
    178static int __cbas_ec_probe(struct platform_device *pdev)
    179{
    180	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
    181	struct input_dev *input;
    182	bool base_supported;
    183	int error;
    184
    185	error = cbas_ec_query_base(ec, false, &base_supported);
    186	if (error)
    187		return error;
    188
    189	if (!base_supported)
    190		return -ENXIO;
    191
    192	input = devm_input_allocate_device(&pdev->dev);
    193	if (!input)
    194		return -ENOMEM;
    195
    196	input->name = "Whiskers Tablet Mode Switch";
    197	input->id.bustype = BUS_HOST;
    198
    199	input_set_capability(input, EV_SW, SW_TABLET_MODE);
    200
    201	error = input_register_device(input);
    202	if (error) {
    203		dev_err(&pdev->dev, "cannot register input device: %d\n",
    204			error);
    205		return error;
    206	}
    207
    208	/* Seed the state */
    209	error = cbas_ec_query_base(ec, true, &cbas_ec.base_present);
    210	if (error) {
    211		dev_err(&pdev->dev, "cannot query base state: %d\n", error);
    212		return error;
    213	}
    214
    215	if (!cbas_ec.base_present)
    216		cbas_ec.base_folded = false;
    217
    218	dev_dbg(&pdev->dev, "%s: base: %d, folded: %d\n", __func__,
    219		cbas_ec.base_present, cbas_ec.base_folded);
    220
    221	input_report_switch(input, SW_TABLET_MODE,
    222			    !cbas_ec.base_present || cbas_ec.base_folded);
    223
    224	cbas_ec_set_input(input);
    225
    226	cbas_ec.dev = &pdev->dev;
    227	cbas_ec.notifier.notifier_call = cbas_ec_notify;
    228	error = blocking_notifier_chain_register(&ec->event_notifier,
    229						 &cbas_ec.notifier);
    230	if (error) {
    231		dev_err(&pdev->dev, "cannot register notifier: %d\n", error);
    232		cbas_ec_set_input(NULL);
    233		return error;
    234	}
    235
    236	device_init_wakeup(&pdev->dev, true);
    237	return 0;
    238}
    239
    240static int cbas_ec_probe(struct platform_device *pdev)
    241{
    242	int retval;
    243
    244	mutex_lock(&cbas_ec_reglock);
    245
    246	if (cbas_ec.input) {
    247		retval = -EBUSY;
    248		goto out;
    249	}
    250
    251	retval = __cbas_ec_probe(pdev);
    252
    253out:
    254	mutex_unlock(&cbas_ec_reglock);
    255	return retval;
    256}
    257
    258static int cbas_ec_remove(struct platform_device *pdev)
    259{
    260	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
    261
    262	mutex_lock(&cbas_ec_reglock);
    263
    264	blocking_notifier_chain_unregister(&ec->event_notifier,
    265					   &cbas_ec.notifier);
    266	cbas_ec_set_input(NULL);
    267
    268	mutex_unlock(&cbas_ec_reglock);
    269	return 0;
    270}
    271
    272static const struct acpi_device_id cbas_ec_acpi_ids[] = {
    273	{ "GOOG000B", 0 },
    274	{ }
    275};
    276MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
    277
    278#ifdef CONFIG_OF
    279static const struct of_device_id cbas_ec_of_match[] = {
    280	{ .compatible = "google,cros-cbas" },
    281	{ },
    282};
    283MODULE_DEVICE_TABLE(of, cbas_ec_of_match);
    284#endif
    285
    286static struct platform_driver cbas_ec_driver = {
    287	.probe = cbas_ec_probe,
    288	.remove = cbas_ec_remove,
    289	.driver = {
    290		.name = "cbas_ec",
    291		.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
    292		.of_match_table = of_match_ptr(cbas_ec_of_match),
    293		.pm = &cbas_ec_pm_ops,
    294	},
    295};
    296
    297#define MAX_BRIGHTNESS 100
    298
    299struct hammer_kbd_leds {
    300	struct led_classdev cdev;
    301	struct hid_device *hdev;
    302	u8 buf[2] ____cacheline_aligned;
    303};
    304
    305static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev,
    306		enum led_brightness br)
    307{
    308	struct hammer_kbd_leds *led = container_of(cdev,
    309						   struct hammer_kbd_leds,
    310						   cdev);
    311	int ret;
    312
    313	led->buf[0] = 0;
    314	led->buf[1] = br;
    315
    316	/*
    317	 * Request USB HID device to be in Full On mode, so that sending
    318	 * hardware output report and hardware raw request won't fail.
    319	 */
    320	ret = hid_hw_power(led->hdev, PM_HINT_FULLON);
    321	if (ret < 0) {
    322		hid_err(led->hdev, "failed: device not resumed %d\n", ret);
    323		return ret;
    324	}
    325
    326	ret = hid_hw_output_report(led->hdev, led->buf, sizeof(led->buf));
    327	if (ret == -ENOSYS)
    328		ret = hid_hw_raw_request(led->hdev, 0, led->buf,
    329					 sizeof(led->buf),
    330					 HID_OUTPUT_REPORT,
    331					 HID_REQ_SET_REPORT);
    332	if (ret < 0)
    333		hid_err(led->hdev, "failed to set keyboard backlight: %d\n",
    334			ret);
    335
    336	/* Request USB HID device back to Normal Mode. */
    337	hid_hw_power(led->hdev, PM_HINT_NORMAL);
    338
    339	return ret;
    340}
    341
    342static int hammer_register_leds(struct hid_device *hdev)
    343{
    344	struct hammer_kbd_leds *kbd_backlight;
    345
    346	kbd_backlight = devm_kzalloc(&hdev->dev, sizeof(*kbd_backlight),
    347				     GFP_KERNEL);
    348	if (!kbd_backlight)
    349		return -ENOMEM;
    350
    351	kbd_backlight->hdev = hdev;
    352	kbd_backlight->cdev.name = "hammer::kbd_backlight";
    353	kbd_backlight->cdev.max_brightness = MAX_BRIGHTNESS;
    354	kbd_backlight->cdev.brightness_set_blocking =
    355		hammer_kbd_brightness_set_blocking;
    356	kbd_backlight->cdev.flags = LED_HW_PLUGGABLE;
    357
    358	/* Set backlight to 0% initially. */
    359	hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0);
    360
    361	return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
    362}
    363
    364#define HID_UP_GOOGLEVENDOR	0xffd10000
    365#define HID_VD_KBD_FOLDED	0x00000019
    366#define HID_USAGE_KBD_FOLDED	(HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
    367
    368/* HID usage for keyboard backlight (Alphanumeric display brightness) */
    369#define HID_AD_BRIGHTNESS	0x00140046
    370
    371static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
    372				struct hid_field *field,
    373				struct hid_usage *usage,
    374				unsigned long **bit, int *max)
    375{
    376	if (usage->hid == HID_USAGE_KBD_FOLDED) {
    377		/*
    378		 * We do not want to have this usage mapped as it will get
    379		 * mixed in with "base attached" signal and delivered over
    380		 * separate input device for tablet switch mode.
    381		 */
    382		return -1;
    383	}
    384
    385	return 0;
    386}
    387
    388static void hammer_folded_event(struct hid_device *hdev, bool folded)
    389{
    390	unsigned long flags;
    391
    392	spin_lock_irqsave(&cbas_ec_lock, flags);
    393
    394	/*
    395	 * If we are getting events from Whiskers that means that it
    396	 * is attached to the lid.
    397	 */
    398	cbas_ec.base_present = true;
    399	cbas_ec.base_folded = folded;
    400	hid_dbg(hdev, "%s: base: %d, folded: %d\n", __func__,
    401		cbas_ec.base_present, cbas_ec.base_folded);
    402
    403	if (cbas_ec.input) {
    404		input_report_switch(cbas_ec.input, SW_TABLET_MODE, folded);
    405		input_sync(cbas_ec.input);
    406	}
    407
    408	spin_unlock_irqrestore(&cbas_ec_lock, flags);
    409}
    410
    411static int hammer_event(struct hid_device *hid, struct hid_field *field,
    412			struct hid_usage *usage, __s32 value)
    413{
    414	if (usage->hid == HID_USAGE_KBD_FOLDED) {
    415		hammer_folded_event(hid, value);
    416		return 1; /* We handled this event */
    417	}
    418
    419	return 0;
    420}
    421
    422static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
    423			unsigned application, unsigned usage)
    424{
    425	struct hid_report_enum *re = &hdev->report_enum[report_type];
    426	struct hid_report *report;
    427	int i, j;
    428
    429	list_for_each_entry(report, &re->report_list, list) {
    430		if (report->application != application)
    431			continue;
    432
    433		for (i = 0; i < report->maxfield; i++) {
    434			struct hid_field *field = report->field[i];
    435
    436			for (j = 0; j < field->maxusage; j++)
    437				if (field->usage[j].hid == usage)
    438					return true;
    439		}
    440	}
    441
    442	return false;
    443}
    444
    445static bool hammer_has_folded_event(struct hid_device *hdev)
    446{
    447	return hammer_has_usage(hdev, HID_INPUT_REPORT,
    448				HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
    449}
    450
    451static bool hammer_has_backlight_control(struct hid_device *hdev)
    452{
    453	return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
    454				HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
    455}
    456
    457static void hammer_get_folded_state(struct hid_device *hdev)
    458{
    459	struct hid_report *report;
    460	char *buf;
    461	int len, rlen;
    462	int a;
    463
    464	report = hdev->report_enum[HID_INPUT_REPORT].report_id_hash[0x0];
    465
    466	if (!report || report->maxfield < 1)
    467		return;
    468
    469	len = hid_report_len(report) + 1;
    470
    471	buf = kmalloc(len, GFP_KERNEL);
    472	if (!buf)
    473		return;
    474
    475	rlen = hid_hw_raw_request(hdev, report->id, buf, len, report->type, HID_REQ_GET_REPORT);
    476
    477	if (rlen != len) {
    478		hid_warn(hdev, "Unable to read base folded state: %d (expected %d)\n", rlen, len);
    479		goto out;
    480	}
    481
    482	for (a = 0; a < report->maxfield; a++) {
    483		struct hid_field *field = report->field[a];
    484
    485		if (field->usage->hid == HID_USAGE_KBD_FOLDED) {
    486			u32 value = hid_field_extract(hdev, buf+1,
    487					field->report_offset, field->report_size);
    488
    489			hammer_folded_event(hdev, value);
    490			break;
    491		}
    492	}
    493
    494out:
    495	kfree(buf);
    496}
    497
    498static void hammer_stop(void *hdev)
    499{
    500	hid_hw_stop(hdev);
    501}
    502
    503static int hammer_probe(struct hid_device *hdev,
    504			const struct hid_device_id *id)
    505{
    506	struct vivaldi_data *vdata;
    507	int error;
    508
    509	vdata = devm_kzalloc(&hdev->dev, sizeof(*vdata), GFP_KERNEL);
    510	if (!vdata)
    511		return -ENOMEM;
    512
    513	hid_set_drvdata(hdev, vdata);
    514
    515	error = hid_parse(hdev);
    516	if (error)
    517		return error;
    518
    519	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
    520	if (error)
    521		return error;
    522
    523	error = devm_add_action(&hdev->dev, hammer_stop, hdev);
    524	if (error)
    525		return error;
    526
    527	/*
    528	 * We always want to poll for, and handle tablet mode events from
    529	 * devices that have folded usage, even when nobody has opened the input
    530	 * device. This also prevents the hid core from dropping early tablet
    531	 * mode events from the device.
    532	 */
    533	if (hammer_has_folded_event(hdev)) {
    534		hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
    535		error = hid_hw_open(hdev);
    536		if (error)
    537			return error;
    538
    539		hammer_get_folded_state(hdev);
    540	}
    541
    542	if (hammer_has_backlight_control(hdev)) {
    543		error = hammer_register_leds(hdev);
    544		if (error)
    545			hid_warn(hdev,
    546				"Failed to register keyboard backlight: %d\n",
    547				error);
    548	}
    549
    550	return 0;
    551}
    552
    553static void hammer_remove(struct hid_device *hdev)
    554{
    555	unsigned long flags;
    556
    557	if (hammer_has_folded_event(hdev)) {
    558		hid_hw_close(hdev);
    559
    560		/*
    561		 * If we are disconnecting then most likely Whiskers is
    562		 * being removed. Even if it is not removed, without proper
    563		 * keyboard we should not stay in clamshell mode.
    564		 *
    565		 * The reason for doing it here and not waiting for signal
    566		 * from EC, is that on some devices there are high leakage
    567		 * on Whiskers pins and we do not detect disconnect reliably,
    568		 * resulting in devices being stuck in clamshell mode.
    569		 */
    570		spin_lock_irqsave(&cbas_ec_lock, flags);
    571		if (cbas_ec.input && cbas_ec.base_present) {
    572			input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
    573			input_sync(cbas_ec.input);
    574		}
    575		cbas_ec.base_present = false;
    576		spin_unlock_irqrestore(&cbas_ec_lock, flags);
    577	}
    578
    579	/* Unregistering LEDs and stopping the hardware is done via devm */
    580}
    581
    582static const struct hid_device_id hammer_devices[] = {
    583	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    584		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) },
    585	{ HID_DEVICE(BUS_USB, HID_GROUP_VIVALDI,
    586		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_EEL) },
    587	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    588		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
    589	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    590		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) },
    591	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    592		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) },
    593	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    594		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MOONBALL) },
    595	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    596		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) },
    597	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    598		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WAND) },
    599	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
    600		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WHISKERS) },
    601	{ }
    602};
    603MODULE_DEVICE_TABLE(hid, hammer_devices);
    604
    605static struct hid_driver hammer_driver = {
    606	.name = "hammer",
    607	.id_table = hammer_devices,
    608	.probe = hammer_probe,
    609	.remove = hammer_remove,
    610	.feature_mapping = vivaldi_feature_mapping,
    611	.input_configured = vivaldi_input_configured,
    612	.input_mapping = hammer_input_mapping,
    613	.event = hammer_event,
    614};
    615
    616static int __init hammer_init(void)
    617{
    618	int error;
    619
    620	error = platform_driver_register(&cbas_ec_driver);
    621	if (error)
    622		return error;
    623
    624	error = hid_register_driver(&hammer_driver);
    625	if (error) {
    626		platform_driver_unregister(&cbas_ec_driver);
    627		return error;
    628	}
    629
    630	return 0;
    631}
    632module_init(hammer_init);
    633
    634static void __exit hammer_exit(void)
    635{
    636	hid_unregister_driver(&hammer_driver);
    637	platform_driver_unregister(&cbas_ec_driver);
    638}
    639module_exit(hammer_exit);
    640
    641MODULE_LICENSE("GPL");