n64joy.c 7.8 KB

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