1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Manuel Jander. |
4 | * |
5 | * Based on the work of: |
6 | * Vojtech Pavlik |
7 | * Raymond Ingles |
8 | * |
9 | * Should you need to contact me, the author, you can do so either by |
10 | * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: |
11 | * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic |
12 | * |
13 | * Based 90% on Vojtech Pavlik pcigame driver. |
14 | * Merged and modified by Manuel Jander, for the OpenVortex |
15 | * driver. (email: mjander@embedded.cl). |
16 | */ |
17 | |
18 | #include <linux/time.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/init.h> |
21 | #include <sound/core.h> |
22 | #include "au88x0.h" |
23 | #include <linux/gameport.h> |
24 | #include <linux/export.h> |
25 | |
26 | #if IS_REACHABLE(CONFIG_GAMEPORT) |
27 | |
28 | #define VORTEX_GAME_DWAIT 20 /* 20 ms */ |
29 | |
30 | static unsigned char vortex_game_read(struct gameport *gameport) |
31 | { |
32 | vortex_t *vortex = gameport_get_port_data(gameport); |
33 | return hwread(vortex->mmio, VORTEX_GAME_LEGACY); |
34 | } |
35 | |
36 | static void vortex_game_trigger(struct gameport *gameport) |
37 | { |
38 | vortex_t *vortex = gameport_get_port_data(gameport); |
39 | hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff); |
40 | } |
41 | |
42 | static int |
43 | vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons) |
44 | { |
45 | vortex_t *vortex = gameport_get_port_data(gameport); |
46 | int i; |
47 | |
48 | *buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf; |
49 | |
50 | for (i = 0; i < 4; i++) { |
51 | axes[i] = |
52 | hwread(vortex->mmio, VORTEX_GAME_AXIS + (i * AXIS_SIZE)); |
53 | if (axes[i] == AXIS_RANGE) |
54 | axes[i] = -1; |
55 | } |
56 | return 0; |
57 | } |
58 | |
59 | static int vortex_game_open(struct gameport *gameport, int mode) |
60 | { |
61 | vortex_t *vortex = gameport_get_port_data(gameport); |
62 | |
63 | switch (mode) { |
64 | case GAMEPORT_MODE_COOKED: |
65 | hwwrite(vortex->mmio, VORTEX_CTRL2, |
66 | hwread(vortex->mmio, |
67 | VORTEX_CTRL2) | CTRL2_GAME_ADCMODE); |
68 | msleep(VORTEX_GAME_DWAIT); |
69 | return 0; |
70 | case GAMEPORT_MODE_RAW: |
71 | hwwrite(vortex->mmio, VORTEX_CTRL2, |
72 | hwread(vortex->mmio, |
73 | VORTEX_CTRL2) & ~CTRL2_GAME_ADCMODE); |
74 | return 0; |
75 | default: |
76 | return -1; |
77 | } |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | static int vortex_gameport_register(vortex_t *vortex) |
83 | { |
84 | struct gameport *gp; |
85 | |
86 | vortex->gameport = gp = gameport_allocate_port(); |
87 | if (!gp) { |
88 | dev_err(vortex->card->dev, |
89 | "cannot allocate memory for gameport\n" ); |
90 | return -ENOMEM; |
91 | } |
92 | |
93 | gameport_set_name(gameport: gp, name: "AU88x0 Gameport" ); |
94 | gameport_set_phys(gameport: gp, fmt: "pci%s/gameport0" , pci_name(pdev: vortex->pci_dev)); |
95 | gameport_set_dev_parent(gp, &vortex->pci_dev->dev); |
96 | |
97 | gp->read = vortex_game_read; |
98 | gp->trigger = vortex_game_trigger; |
99 | gp->cooked_read = vortex_game_cooked_read; |
100 | gp->open = vortex_game_open; |
101 | |
102 | gameport_set_port_data(gp, vortex); |
103 | gp->fuzz = 64; |
104 | |
105 | gameport_register_port(gp); |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | static void vortex_gameport_unregister(vortex_t * vortex) |
111 | { |
112 | if (vortex->gameport) { |
113 | gameport_unregister_port(gameport: vortex->gameport); |
114 | vortex->gameport = NULL; |
115 | } |
116 | } |
117 | |
118 | #else |
119 | static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; } |
120 | static inline void vortex_gameport_unregister(vortex_t * vortex) { } |
121 | #endif |
122 | |