linux/drivers/input/joystick/n64joy.c
<<
>>
Prefs
   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);
 346