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

n64joy.c (8030B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Support for the four N64 controllers.
      4 *
      5 * Copyright (c) 2021 Lauri Kasanen
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/errno.h>
     11#include <linux/init.h>
     12#include <linux/input.h>
     13#include <linux/limits.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/mutex.h>
     17#include <linux/platform_device.h>
     18#include <linux/slab.h>
     19#include <linux/timer.h>
     20
     21MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
     22MODULE_DESCRIPTION("Driver for N64 controllers");
     23MODULE_LICENSE("GPL");
     24
     25#define PIF_RAM 0x1fc007c0
     26
     27#define SI_DRAM_REG 0
     28#define SI_READ_REG 1
     29#define SI_WRITE_REG 4
     30#define SI_STATUS_REG 6
     31
     32#define SI_STATUS_DMA_BUSY  BIT(0)
     33#define SI_STATUS_IO_BUSY   BIT(1)
     34
     35#define N64_CONTROLLER_ID 0x0500
     36
     37#define MAX_CONTROLLERS 4
     38
     39static const char *n64joy_phys[MAX_CONTROLLERS] = {
     40	"n64joy/port0",
     41	"n64joy/port1",
     42	"n64joy/port2",
     43	"n64joy/port3",
     44};
     45
     46struct n64joy_priv {
     47	u64 si_buf[8] ____cacheline_aligned;
     48	struct timer_list timer;
     49	struct mutex n64joy_mutex;
     50	struct input_dev *n64joy_dev[MAX_CONTROLLERS];
     51	u32 __iomem *reg_base;
     52	u8 n64joy_opened;
     53};
     54
     55struct joydata {
     56	unsigned int: 16; /* unused */
     57	unsigned int err: 2;
     58	unsigned int: 14; /* unused */
     59
     60	union {
     61		u32 data;
     62
     63		struct {
     64			unsigned int a: 1;
     65			unsigned int b: 1;
     66			unsigned int z: 1;
     67			unsigned int start: 1;
     68			unsigned int up: 1;
     69			unsigned int down: 1;
     70			unsigned int left: 1;
     71			unsigned int right: 1;
     72			unsigned int: 2; /* unused */
     73			unsigned int l: 1;
     74			unsigned int r: 1;
     75			unsigned int c_up: 1;
     76			unsigned int c_down: 1;
     77			unsigned int c_left: 1;
     78			unsigned int c_right: 1;
     79			signed int x: 8;
     80			signed int y: 8;
     81		};
     82	};
     83};
     84
     85static void n64joy_write_reg(u32 __iomem *reg_base, const u8 reg, const u32 value)
     86{
     87	writel(value, reg_base + reg);
     88}
     89
     90static u32 n64joy_read_reg(u32 __iomem *reg_base, const u8 reg)
     91{
     92	return readl(reg_base + reg);
     93}
     94
     95static void n64joy_wait_si_dma(u32 __iomem *reg_base)
     96{
     97	while (n64joy_read_reg(reg_base, SI_STATUS_REG) &
     98	       (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY))
     99		cpu_relax();
    100}
    101
    102static void n64joy_exec_pif(struct n64joy_priv *priv, const u64 in[8])
    103{
    104	unsigned long flags;
    105
    106	dma_cache_wback_inv((unsigned long) in, 8 * 8);
    107	dma_cache_inv((unsigned long) priv->si_buf, 8 * 8);
    108
    109	local_irq_save(flags);
    110
    111	n64joy_wait_si_dma(priv->reg_base);
    112
    113	barrier();
    114	n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(in));
    115	barrier();
    116	n64joy_write_reg(priv->reg_base, SI_WRITE_REG, PIF_RAM);
    117	barrier();
    118
    119	n64joy_wait_si_dma(priv->reg_base);
    120
    121	barrier();
    122	n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(priv->si_buf));
    123	barrier();
    124	n64joy_write_reg(priv->reg_base, SI_READ_REG, PIF_RAM);
    125	barrier();
    126
    127	n64joy_wait_si_dma(priv->reg_base);
    128
    129	local_irq_restore(flags);
    130}
    131
    132static const u64 polldata[] ____cacheline_aligned = {
    133	0xff010401ffffffff,
    134	0xff010401ffffffff,
    135	0xff010401ffffffff,
    136	0xff010401ffffffff,
    137	0xfe00000000000000,
    138	0,
    139	0,
    140	1
    141};
    142
    143static void n64joy_poll(struct timer_list *t)
    144{
    145	const struct joydata *data;
    146	struct n64joy_priv *priv = container_of(t, struct n64joy_priv, timer);
    147	struct input_dev *dev;
    148	u32 i;
    149
    150	n64joy_exec_pif(priv, polldata);
    151
    152	data = (struct joydata *) priv->si_buf;
    153
    154	for (i = 0; i < MAX_CONTROLLERS; i++) {
    155		if (!priv->n64joy_dev[i])
    156			continue;
    157
    158		dev = priv->n64joy_dev[i];
    159
    160		/* d-pad */
    161		input_report_key(dev, BTN_DPAD_UP, data[i].up);
    162		input_report_key(dev, BTN_DPAD_DOWN, data[i].down);
    163		input_report_key(dev, BTN_DPAD_LEFT, data[i].left);
    164		input_report_key(dev, BTN_DPAD_RIGHT, data[i].right);
    165
    166		/* c buttons */
    167		input_report_key(dev, BTN_FORWARD, data[i].c_up);
    168		input_report_key(dev, BTN_BACK, data[i].c_down);
    169		input_report_key(dev, BTN_LEFT, data[i].c_left);
    170		input_report_key(dev, BTN_RIGHT, data[i].c_right);
    171
    172		/* matching buttons */
    173		input_report_key(dev, BTN_START, data[i].start);
    174		input_report_key(dev, BTN_Z, data[i].z);
    175
    176		/* remaining ones: a, b, l, r */
    177		input_report_key(dev, BTN_0, data[i].a);
    178		input_report_key(dev, BTN_1, data[i].b);
    179		input_report_key(dev, BTN_2, data[i].l);
    180		input_report_key(dev, BTN_3, data[i].r);
    181
    182		input_report_abs(dev, ABS_X, data[i].x);
    183		input_report_abs(dev, ABS_Y, data[i].y);
    184
    185		input_sync(dev);
    186	}
    187
    188	mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
    189}
    190
    191static int n64joy_open(struct input_dev *dev)
    192{
    193	struct n64joy_priv *priv = input_get_drvdata(dev);
    194	int err;
    195
    196	err = mutex_lock_interruptible(&priv->n64joy_mutex);
    197	if (err)
    198		return err;
    199
    200	if (!priv->n64joy_opened) {
    201		/*
    202		 * We could use the vblank irq, but it's not important if
    203		 * the poll point slightly changes.
    204		 */
    205		timer_setup(&priv->timer, n64joy_poll, 0);
    206		mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
    207	}
    208
    209	priv->n64joy_opened++;
    210
    211	mutex_unlock(&priv->n64joy_mutex);
    212	return err;
    213}
    214
    215static void n64joy_close(struct input_dev *dev)
    216{
    217	struct n64joy_priv *priv = input_get_drvdata(dev);
    218
    219	mutex_lock(&priv->n64joy_mutex);
    220	if (!--priv->n64joy_opened)
    221		del_timer_sync(&priv->timer);
    222	mutex_unlock(&priv->n64joy_mutex);
    223}
    224
    225static const u64 __initconst scandata[] ____cacheline_aligned = {
    226	0xff010300ffffffff,
    227	0xff010300ffffffff,
    228	0xff010300ffffffff,
    229	0xff010300ffffffff,
    230	0xfe00000000000000,
    231	0,
    232	0,
    233	1
    234};
    235
    236/*
    237 * The target device is embedded and RAM-constrained. We save RAM
    238 * by initializing in __init code that gets dropped late in boot.
    239 * For the same reason there is no module or unloading support.
    240 */
    241static int __init n64joy_probe(struct platform_device *pdev)
    242{
    243	const struct joydata *data;
    244	struct n64joy_priv *priv;
    245	struct input_dev *dev;
    246	int err = 0;
    247	u32 i, j, found = 0;
    248
    249	priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
    250	if (!priv)
    251		return -ENOMEM;
    252	mutex_init(&priv->n64joy_mutex);
    253
    254	priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
    255	if (IS_ERR(priv->reg_base)) {
    256		err = PTR_ERR(priv->reg_base);
    257		goto fail;
    258	}
    259
    260	/* The controllers are not hotpluggable, so we can scan in init */
    261	n64joy_exec_pif(priv, scandata);
    262
    263	data = (struct joydata *) priv->si_buf;
    264
    265	for (i = 0; i < MAX_CONTROLLERS; i++) {
    266		if (!data[i].err && data[i].data >> 16 == N64_CONTROLLER_ID) {
    267			found++;
    268
    269			dev = priv->n64joy_dev[i] = input_allocate_device();
    270			if (!priv->n64joy_dev[i]) {
    271				err = -ENOMEM;
    272				goto fail;
    273			}
    274
    275			input_set_drvdata(dev, priv);
    276
    277			dev->name = "N64 controller";
    278			dev->phys = n64joy_phys[i];
    279			dev->id.bustype = BUS_HOST;
    280			dev->id.vendor = 0;
    281			dev->id.product = data[i].data >> 16;
    282			dev->id.version = 0;
    283			dev->dev.parent = &pdev->dev;
    284
    285			dev->open = n64joy_open;
    286			dev->close = n64joy_close;
    287
    288			/* d-pad */
    289			input_set_capability(dev, EV_KEY, BTN_DPAD_UP);
    290			input_set_capability(dev, EV_KEY, BTN_DPAD_DOWN);
    291			input_set_capability(dev, EV_KEY, BTN_DPAD_LEFT);
    292			input_set_capability(dev, EV_KEY, BTN_DPAD_RIGHT);
    293			/* c buttons */
    294			input_set_capability(dev, EV_KEY, BTN_LEFT);
    295			input_set_capability(dev, EV_KEY, BTN_RIGHT);
    296			input_set_capability(dev, EV_KEY, BTN_FORWARD);
    297			input_set_capability(dev, EV_KEY, BTN_BACK);
    298			/* matching buttons */
    299			input_set_capability(dev, EV_KEY, BTN_START);
    300			input_set_capability(dev, EV_KEY, BTN_Z);
    301			/* remaining ones: a, b, l, r */
    302			input_set_capability(dev, EV_KEY, BTN_0);
    303			input_set_capability(dev, EV_KEY, BTN_1);
    304			input_set_capability(dev, EV_KEY, BTN_2);
    305			input_set_capability(dev, EV_KEY, BTN_3);
    306
    307			for (j = 0; j < 2; j++)
    308				input_set_abs_params(dev, ABS_X + j,
    309						     S8_MIN, S8_MAX, 0, 0);
    310
    311			err = input_register_device(dev);
    312			if (err) {
    313				input_free_device(dev);
    314				goto fail;
    315			}
    316		}
    317	}
    318
    319	pr_info("%u controller(s) connected\n", found);
    320
    321	if (!found)
    322		return -ENODEV;
    323
    324	return 0;
    325fail:
    326	for (i = 0; i < MAX_CONTROLLERS; i++) {
    327		if (!priv->n64joy_dev[i])
    328			continue;
    329		input_unregister_device(priv->n64joy_dev[i]);
    330	}
    331	return err;
    332}
    333
    334static struct platform_driver n64joy_driver = {
    335	.driver = {
    336		.name = "n64joy",
    337	},
    338};
    339
    340static int __init n64joy_init(void)
    341{
    342	return platform_driver_probe(&n64joy_driver, n64joy_probe);
    343}
    344
    345module_init(n64joy_init);