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);