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

goldfish_events.c (4767B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2007 Google, Inc.
      4 * Copyright (C) 2012 Intel, Inc.
      5 */
      6
      7#include <linux/module.h>
      8#include <linux/interrupt.h>
      9#include <linux/types.h>
     10#include <linux/input.h>
     11#include <linux/kernel.h>
     12#include <linux/platform_device.h>
     13#include <linux/slab.h>
     14#include <linux/irq.h>
     15#include <linux/io.h>
     16#include <linux/acpi.h>
     17
     18enum {
     19	REG_READ        = 0x00,
     20	REG_SET_PAGE    = 0x00,
     21	REG_LEN         = 0x04,
     22	REG_DATA        = 0x08,
     23
     24	PAGE_NAME       = 0x00000,
     25	PAGE_EVBITS     = 0x10000,
     26	PAGE_ABSDATA    = 0x20000 | EV_ABS,
     27};
     28
     29struct event_dev {
     30	struct input_dev *input;
     31	int irq;
     32	void __iomem *addr;
     33	char name[];
     34};
     35
     36static irqreturn_t events_interrupt(int irq, void *dev_id)
     37{
     38	struct event_dev *edev = dev_id;
     39	unsigned int type, code, value;
     40
     41	type = __raw_readl(edev->addr + REG_READ);
     42	code = __raw_readl(edev->addr + REG_READ);
     43	value = __raw_readl(edev->addr + REG_READ);
     44
     45	input_event(edev->input, type, code, value);
     46	input_sync(edev->input);
     47	return IRQ_HANDLED;
     48}
     49
     50static void events_import_bits(struct event_dev *edev,
     51			unsigned long bits[], unsigned int type, size_t count)
     52{
     53	void __iomem *addr = edev->addr;
     54	int i, j;
     55	size_t size;
     56	uint8_t val;
     57
     58	__raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE);
     59
     60	size = __raw_readl(addr + REG_LEN) * 8;
     61	if (size < count)
     62		count = size;
     63
     64	addr += REG_DATA;
     65	for (i = 0; i < count; i += 8) {
     66		val = __raw_readb(addr++);
     67		for (j = 0; j < 8; j++)
     68			if (val & 1 << j)
     69				set_bit(i + j, bits);
     70	}
     71}
     72
     73static void events_import_abs_params(struct event_dev *edev)
     74{
     75	struct input_dev *input_dev = edev->input;
     76	void __iomem *addr = edev->addr;
     77	u32 val[4];
     78	int count;
     79	int i, j;
     80
     81	__raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
     82
     83	count = __raw_readl(addr + REG_LEN) / sizeof(val);
     84	if (count > ABS_MAX)
     85		count = ABS_MAX;
     86
     87	for (i = 0; i < count; i++) {
     88		if (!test_bit(i, input_dev->absbit))
     89			continue;
     90
     91		for (j = 0; j < ARRAY_SIZE(val); j++) {
     92			int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32);
     93
     94			val[j] = __raw_readl(edev->addr + REG_DATA + offset);
     95		}
     96
     97		input_set_abs_params(input_dev, i,
     98				     val[0], val[1], val[2], val[3]);
     99	}
    100}
    101
    102static int events_probe(struct platform_device *pdev)
    103{
    104	struct input_dev *input_dev;
    105	struct event_dev *edev;
    106	struct resource *res;
    107	unsigned int keymapnamelen;
    108	void __iomem *addr;
    109	int irq;
    110	int i;
    111	int error;
    112
    113	irq = platform_get_irq(pdev, 0);
    114	if (irq < 0)
    115		return -EINVAL;
    116
    117	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    118	if (!res)
    119		return -EINVAL;
    120
    121	addr = devm_ioremap(&pdev->dev, res->start, 4096);
    122	if (!addr)
    123		return -ENOMEM;
    124
    125	__raw_writel(PAGE_NAME, addr + REG_SET_PAGE);
    126	keymapnamelen = __raw_readl(addr + REG_LEN);
    127
    128	edev = devm_kzalloc(&pdev->dev,
    129			    sizeof(struct event_dev) + keymapnamelen + 1,
    130			    GFP_KERNEL);
    131	if (!edev)
    132		return -ENOMEM;
    133
    134	input_dev = devm_input_allocate_device(&pdev->dev);
    135	if (!input_dev)
    136		return -ENOMEM;
    137
    138	edev->input = input_dev;
    139	edev->addr = addr;
    140	edev->irq = irq;
    141
    142	for (i = 0; i < keymapnamelen; i++)
    143		edev->name[i] = __raw_readb(edev->addr + REG_DATA + i);
    144
    145	pr_debug("%s: keymap=%s\n", __func__, edev->name);
    146
    147	input_dev->name = edev->name;
    148	input_dev->id.bustype = BUS_HOST;
    149
    150	events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
    151	events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
    152	events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
    153	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
    154	events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
    155	events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
    156	events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
    157	events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX);
    158	events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX);
    159
    160	events_import_abs_params(edev);
    161
    162	error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0,
    163				 "goldfish-events-keypad", edev);
    164	if (error)
    165		return error;
    166
    167	error = input_register_device(input_dev);
    168	if (error)
    169		return error;
    170
    171	return 0;
    172}
    173
    174static const struct of_device_id goldfish_events_of_match[] = {
    175	{ .compatible = "google,goldfish-events-keypad", },
    176	{},
    177};
    178MODULE_DEVICE_TABLE(of, goldfish_events_of_match);
    179
    180#ifdef CONFIG_ACPI
    181static const struct acpi_device_id goldfish_events_acpi_match[] = {
    182	{ "GFSH0002", 0 },
    183	{ },
    184};
    185MODULE_DEVICE_TABLE(acpi, goldfish_events_acpi_match);
    186#endif
    187
    188static struct platform_driver events_driver = {
    189	.probe	= events_probe,
    190	.driver	= {
    191		.name	= "goldfish_events",
    192		.of_match_table = goldfish_events_of_match,
    193		.acpi_match_table = ACPI_PTR(goldfish_events_acpi_match),
    194	},
    195};
    196
    197module_platform_driver(events_driver);
    198
    199MODULE_AUTHOR("Brian Swetland");
    200MODULE_DESCRIPTION("Goldfish Event Device");
    201MODULE_LICENSE("GPL");