aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/gameport
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/gameport')
-rw-r--r--drivers/input/gameport/Kconfig90
-rw-r--r--drivers/input/gameport/Makefile13
-rw-r--r--drivers/input/gameport/cs461x.c322
-rw-r--r--drivers/input/gameport/emu10k1-gp.c132
-rw-r--r--drivers/input/gameport/fm801-gp.c163
-rw-r--r--drivers/input/gameport/gameport.c797
-rw-r--r--drivers/input/gameport/lightning.c344
-rw-r--r--drivers/input/gameport/ns558.c291
-rw-r--r--drivers/input/gameport/vortex.c186
9 files changed, 2338 insertions, 0 deletions
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
new file mode 100644
index 000000000000..6282f460aba0
--- /dev/null
+++ b/drivers/input/gameport/Kconfig
@@ -0,0 +1,90 @@
1#
2# Gameport configuration
3#
4config GAMEPORT
5 tristate "Gameport support"
6 ---help---
7 Gameport support is for the standard 15-pin PC gameport. If you
8 have a joystick, gamepad, gameport card, a soundcard with a gameport
9 or anything else that uses the gameport, say Y or M here and also to
10 at least one of the hardware specific drivers.
11
12 For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1,
13 S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport
14 support is provided by the sound drivers, so you won't need any
15 from the below listed modules. You still need to say Y here.
16
17 If unsure, say Y.
18
19 To compile this driver as a module, choose M here: the
20 module will be called gameport.
21
22if GAMEPORT
23
24config GAMEPORT_NS558
25 tristate "Classic ISA and PnP gameport support"
26 help
27 Say Y here if you have an ISA or PnP gameport.
28
29 If unsure, say Y.
30
31 To compile this driver as a module, choose M here: the
32 module will be called ns558.
33
34config GAMEPORT_L4
35 tristate "PDPI Lightning 4 gamecard support"
36 help
37 Say Y here if you have a PDPI Lightning 4 gamecard.
38
39 To compile this driver as a module, choose M here: the
40 module will be called lightning.
41
42config GAMEPORT_EMU10K1
43 tristate "SB Live and Audigy gameport support"
44 depends on PCI
45 help
46 Say Y here if you have a SoundBlaster Live! or SoundBlaster
47 Audigy card and want to use its gameport.
48
49 To compile this driver as a module, choose M here: the
50 module will be called emu10k1-gp.
51
52config GAMEPORT_VORTEX
53 tristate "Aureal Vortex, Vortex 2 gameport support"
54 depends on PCI
55 help
56 Say Y here if you have an Aureal Vortex 1 or 2 card and want
57 to use its gameport.
58
59 To compile this driver as a module, choose M here: the
60 module will be called vortex.
61
62config GAMEPORT_FM801
63 tristate "ForteMedia FM801 gameport support"
64 depends on PCI
65
66config GAMEPORT_CS461X
67 tristate "Crystal SoundFusion gameport support"
68 depends on PCI
69
70endif
71
72# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
73# in every .config. Please don't touch it. It is here to handle an
74# unusual dependency between GAMEPORT and sound drivers.
75#
76# Some sound drivers call gameport functions. If GAMEPORT is
77# not selected, empty stubs are provided for the functions and all is
78# well.
79# If GAMEPORT is built in, everything is fine.
80# If GAMEPORT is a module, however, it would need to be loaded for the
81# sound driver to be able to link properly. Therefore, the sound
82# driver must be a module as well in that case. Since there's no way
83# to express that directly in Kconfig, we use SOUND_GAMEPORT to
84# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
85# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
86# GAMEPORT is 'y' or 'n', it can be anything".
87config SOUND_GAMEPORT
88 tristate
89 default m if GAMEPORT=m
90 default y
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
new file mode 100644
index 000000000000..5367b4267adf
--- /dev/null
+++ b/drivers/input/gameport/Makefile
@@ -0,0 +1,13 @@
1#
2# Makefile for the gameport drivers.
3#
4
5# Each configuration option enables a list of files.
6
7obj-$(CONFIG_GAMEPORT) += gameport.o
8obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
9obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
10obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
11obj-$(CONFIG_GAMEPORT_L4) += lightning.o
12obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
13obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
new file mode 100644
index 000000000000..d4013ff98623
--- /dev/null
+++ b/drivers/input/gameport/cs461x.c
@@ -0,0 +1,322 @@
1/*
2 The all defines and part of code (such as cs461x_*) are
3 contributed from ALSA 0.5.8 sources.
4 See http://www.alsa-project.org/ for sources
5
6 Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
7*/
8
9#include <asm/io.h>
10
11#include <linux/module.h>
12#include <linux/ioport.h>
13#include <linux/config.h>
14#include <linux/init.h>
15#include <linux/gameport.h>
16#include <linux/slab.h>
17#include <linux/pci.h>
18
19MODULE_AUTHOR("Victor Krapivin");
20MODULE_LICENSE("GPL");
21
22/*
23 These options are experimental
24
25#define CS461X_FULL_MAP
26*/
27
28
29#ifndef PCI_VENDOR_ID_CIRRUS
30#define PCI_VENDOR_ID_CIRRUS 0x1013
31#endif
32#ifndef PCI_DEVICE_ID_CIRRUS_4610
33#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
34#endif
35#ifndef PCI_DEVICE_ID_CIRRUS_4612
36#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
37#endif
38#ifndef PCI_DEVICE_ID_CIRRUS_4615
39#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
40#endif
41
42/* Registers */
43
44#define BA0_JSPT 0x00000480
45#define BA0_JSCTL 0x00000484
46#define BA0_JSC1 0x00000488
47#define BA0_JSC2 0x0000048C
48#define BA0_JSIO 0x000004A0
49
50/* Bits for JSPT */
51
52#define JSPT_CAX 0x00000001
53#define JSPT_CAY 0x00000002
54#define JSPT_CBX 0x00000004
55#define JSPT_CBY 0x00000008
56#define JSPT_BA1 0x00000010
57#define JSPT_BA2 0x00000020
58#define JSPT_BB1 0x00000040
59#define JSPT_BB2 0x00000080
60
61/* Bits for JSCTL */
62
63#define JSCTL_SP_MASK 0x00000003
64#define JSCTL_SP_SLOW 0x00000000
65#define JSCTL_SP_MEDIUM_SLOW 0x00000001
66#define JSCTL_SP_MEDIUM_FAST 0x00000002
67#define JSCTL_SP_FAST 0x00000003
68#define JSCTL_ARE 0x00000004
69
70/* Data register pairs masks */
71
72#define JSC1_Y1V_MASK 0x0000FFFF
73#define JSC1_X1V_MASK 0xFFFF0000
74#define JSC1_Y1V_SHIFT 0
75#define JSC1_X1V_SHIFT 16
76#define JSC2_Y2V_MASK 0x0000FFFF
77#define JSC2_X2V_MASK 0xFFFF0000
78#define JSC2_Y2V_SHIFT 0
79#define JSC2_X2V_SHIFT 16
80
81/* JS GPIO */
82
83#define JSIO_DAX 0x00000001
84#define JSIO_DAY 0x00000002
85#define JSIO_DBX 0x00000004
86#define JSIO_DBY 0x00000008
87#define JSIO_AXOE 0x00000010
88#define JSIO_AYOE 0x00000020
89#define JSIO_BXOE 0x00000040
90#define JSIO_BYOE 0x00000080
91
92/*
93 The card initialization code is obfuscated; the module cs461x
94 need to be loaded after ALSA modules initialized and something
95 played on the CS 4610 chip (see sources for details of CS4610
96 initialization code from ALSA)
97*/
98
99/* Card specific definitions */
100
101#define CS461X_BA0_SIZE 0x2000
102#define CS461X_BA1_DATA0_SIZE 0x3000
103#define CS461X_BA1_DATA1_SIZE 0x3800
104#define CS461X_BA1_PRG_SIZE 0x7000
105#define CS461X_BA1_REG_SIZE 0x0100
106
107#define BA1_SP_DMEM0 0x00000000
108#define BA1_SP_DMEM1 0x00010000
109#define BA1_SP_PMEM 0x00020000
110#define BA1_SP_REG 0x00030000
111
112#define BA1_DWORD_SIZE (13 * 1024 + 512)
113#define BA1_MEMORY_COUNT 3
114
115/*
116 Only one CS461x card is still suppoted; the code requires
117 redesign to avoid this limitatuion.
118*/
119
120static unsigned long ba0_addr;
121static unsigned int __iomem *ba0;
122
123#ifdef CS461X_FULL_MAP
124static unsigned long ba1_addr;
125static union ba1_t {
126 struct {
127 unsigned int __iomem *data0;
128 unsigned int __iomem *data1;
129 unsigned int __iomem *pmem;
130 unsigned int __iomem *reg;
131 } name;
132 unsigned int __iomem *idx[4];
133} ba1;
134
135static void cs461x_poke(unsigned long reg, unsigned int val)
136{
137 writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
138}
139
140static unsigned int cs461x_peek(unsigned long reg)
141{
142 return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
143}
144
145#endif
146
147static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
148{
149 writel(val, &ba0[reg >> 2]);
150}
151
152static unsigned int cs461x_peekBA0(unsigned long reg)
153{
154 return readl(&ba0[reg >> 2]);
155}
156
157static int cs461x_free(struct pci_dev *pdev)
158{
159 struct gameport *port = pci_get_drvdata(pdev);
160
161 if (port)
162 gameport_unregister_port(port);
163
164 if (ba0) iounmap(ba0);
165#ifdef CS461X_FULL_MAP
166 if (ba1.name.data0) iounmap(ba1.name.data0);
167 if (ba1.name.data1) iounmap(ba1.name.data1);
168 if (ba1.name.pmem) iounmap(ba1.name.pmem);
169 if (ba1.name.reg) iounmap(ba1.name.reg);
170#endif
171 return 0;
172}
173
174static void cs461x_gameport_trigger(struct gameport *gameport)
175{
176 cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
177}
178
179static unsigned char cs461x_gameport_read(struct gameport *gameport)
180{
181 return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
182}
183
184static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
185{
186 unsigned js1, js2, jst;
187
188 js1 = cs461x_peekBA0(BA0_JSC1);
189 js2 = cs461x_peekBA0(BA0_JSC2);
190 jst = cs461x_peekBA0(BA0_JSPT);
191
192 *buttons = (~jst >> 4) & 0x0F;
193
194 axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
195 axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
196 axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
197 axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
198
199 for(jst=0;jst<4;++jst)
200 if(axes[jst]==0xFFFF) axes[jst] = -1;
201 return 0;
202}
203
204static int cs461x_gameport_open(struct gameport *gameport, int mode)
205{
206 switch (mode) {
207 case GAMEPORT_MODE_COOKED:
208 case GAMEPORT_MODE_RAW:
209 return 0;
210 default:
211 return -1;
212 }
213 return 0;
214}
215
216static struct pci_device_id cs461x_pci_tbl[] = {
217 { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
218 { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
219 { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
220 { 0, }
221};
222MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
223
224static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
225{
226 int rc;
227 struct gameport* port;
228
229 rc = pci_enable_device(pdev);
230 if (rc) {
231 printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
232 pdev->bus->number, pdev->devfn, rc);
233 return rc;
234 }
235
236 ba0_addr = pci_resource_start(pdev, 0);
237#ifdef CS461X_FULL_MAP
238 ba1_addr = pci_resource_start(pdev, 1);
239#endif
240 if (ba0_addr == 0 || ba0_addr == ~0
241#ifdef CS461X_FULL_MAP
242 || ba1_addr == 0 || ba1_addr == ~0
243#endif
244 ) {
245 printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
246#ifdef CS461X_FULL_MAP
247 printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
248#endif
249 cs461x_free(pdev);
250 return -ENOMEM;
251 }
252
253 ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
254#ifdef CS461X_FULL_MAP
255 ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
256 ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
257 ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
258 ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
259
260 if (ba0 == NULL || ba1.name.data0 == NULL ||
261 ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
262 ba1.name.reg == NULL) {
263 cs461x_free(pdev);
264 return -ENOMEM;
265 }
266#else
267 if (ba0 == NULL) {
268 cs461x_free(pdev);
269 return -ENOMEM;
270 }
271#endif
272
273 if (!(port = gameport_allocate_port())) {
274 printk(KERN_ERR "cs461x: Memory allocation failed\n");
275 cs461x_free(pdev);
276 return -ENOMEM;
277 }
278
279 pci_set_drvdata(pdev, port);
280
281 port->open = cs461x_gameport_open;
282 port->trigger = cs461x_gameport_trigger;
283 port->read = cs461x_gameport_read;
284 port->cooked_read = cs461x_gameport_cooked_read;
285
286 gameport_set_name(port, "CS416x");
287 gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
288 port->dev.parent = &pdev->dev;
289
290 cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
291 cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
292
293 gameport_register_port(port);
294
295 return 0;
296}
297
298static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
299{
300 cs461x_free(pdev);
301}
302
303static struct pci_driver cs461x_pci_driver = {
304 .name = "CS461x_gameport",
305 .id_table = cs461x_pci_tbl,
306 .probe = cs461x_pci_probe,
307 .remove = __devexit_p(cs461x_pci_remove),
308};
309
310static int __init cs461x_init(void)
311{
312 return pci_register_driver(&cs461x_pci_driver);
313}
314
315static void __exit cs461x_exit(void)
316{
317 pci_unregister_driver(&cs461x_pci_driver);
318}
319
320module_init(cs461x_init);
321module_exit(cs461x_exit);
322
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
new file mode 100644
index 000000000000..a0118038330a
--- /dev/null
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -0,0 +1,132 @@
1/*
2 * $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech Exp $
3 *
4 * Copyright (c) 2001 Vojtech Pavlik
5 */
6
7/*
8 * EMU10k1 - SB Live / Audigy - gameport driver for Linux
9 */
10
11/*
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
28 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
29 */
30
31#include <asm/io.h>
32
33#include <linux/module.h>
34#include <linux/ioport.h>
35#include <linux/config.h>
36#include <linux/init.h>
37#include <linux/gameport.h>
38#include <linux/slab.h>
39#include <linux/pci.h>
40
41MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
42MODULE_DESCRIPTION("EMU10k1 gameport driver");
43MODULE_LICENSE("GPL");
44
45struct emu {
46 struct pci_dev *dev;
47 struct gameport *gameport;
48 int io;
49 int size;
50};
51
52static struct pci_device_id emu_tbl[] = {
53
54 { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
55 { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
56 { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
57 { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */
58 { 0, }
59};
60
61MODULE_DEVICE_TABLE(pci, emu_tbl);
62
63static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
64{
65 int ioport, iolen;
66 struct emu *emu;
67 struct gameport *port;
68
69 if (pci_enable_device(pdev))
70 return -EBUSY;
71
72 ioport = pci_resource_start(pdev, 0);
73 iolen = pci_resource_len(pdev, 0);
74
75 if (!request_region(ioport, iolen, "emu10k1-gp"))
76 return -EBUSY;
77
78 emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
79 port = gameport_allocate_port();
80 if (!emu || !port) {
81 printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
82 release_region(ioport, iolen);
83 kfree(emu);
84 gameport_free_port(port);
85 return -ENOMEM;
86 }
87
88 emu->io = ioport;
89 emu->size = iolen;
90 emu->dev = pdev;
91 emu->gameport = port;
92
93 gameport_set_name(port, "EMU10K1");
94 gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
95 port->dev.parent = &pdev->dev;
96 port->io = ioport;
97
98 pci_set_drvdata(pdev, emu);
99
100 gameport_register_port(port);
101
102 return 0;
103}
104
105static void __devexit emu_remove(struct pci_dev *pdev)
106{
107 struct emu *emu = pci_get_drvdata(pdev);
108
109 gameport_unregister_port(emu->gameport);
110 release_region(emu->io, emu->size);
111 kfree(emu);
112}
113
114static struct pci_driver emu_driver = {
115 .name = "Emu10k1_gameport",
116 .id_table = emu_tbl,
117 .probe = emu_probe,
118 .remove = __devexit_p(emu_remove),
119};
120
121static int __init emu_init(void)
122{
123 return pci_register_driver(&emu_driver);
124}
125
126static void __exit emu_exit(void)
127{
128 pci_unregister_driver(&emu_driver);
129}
130
131module_init(emu_init);
132module_exit(emu_exit);
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
new file mode 100644
index 000000000000..57615bc63906
--- /dev/null
+++ b/drivers/input/gameport/fm801-gp.c
@@ -0,0 +1,163 @@
1/*
2 * FM801 gameport driver for Linux
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23#include <asm/io.h>
24#include <linux/delay.h>
25#include <linux/errno.h>
26#include <linux/ioport.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/pci.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/gameport.h>
33
34#define PCI_VENDOR_ID_FORTEMEDIA 0x1319
35#define PCI_DEVICE_ID_FM801_GP 0x0802
36
37#define HAVE_COOKED
38
39struct fm801_gp {
40 struct gameport *gameport;
41 struct resource *res_port;
42};
43
44#ifdef HAVE_COOKED
45static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
46{
47 unsigned short w;
48
49 w = inw(gameport->io + 2);
50 *buttons = (~w >> 14) & 0x03;
51 axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
52 w = inw(gameport->io + 4);
53 axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
54 w = inw(gameport->io + 6);
55 *buttons |= ((~w >> 14) & 0x03) << 2;
56 axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
57 w = inw(gameport->io + 8);
58 axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
59 outw(0xff, gameport->io); /* reset */
60
61 return 0;
62}
63#endif
64
65static int fm801_gp_open(struct gameport *gameport, int mode)
66{
67 switch (mode) {
68#ifdef HAVE_COOKED
69 case GAMEPORT_MODE_COOKED:
70 return 0;
71#endif
72 case GAMEPORT_MODE_RAW:
73 return 0;
74 default:
75 return -1;
76 }
77
78 return 0;
79}
80
81static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
82{
83 struct fm801_gp *gp;
84 struct gameport *port;
85
86 gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
87 port = gameport_allocate_port();
88 if (!gp || !port) {
89 printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
90 kfree(gp);
91 gameport_free_port(port);
92 return -ENOMEM;
93 }
94
95 pci_enable_device(pci);
96
97 port->open = fm801_gp_open;
98#ifdef HAVE_COOKED
99 port->cooked_read = fm801_gp_cooked_read;
100#endif
101 gameport_set_name(port, "FM801");
102 gameport_set_phys(port, "pci%s/gameport0", pci_name(pci));
103 port->dev.parent = &pci->dev;
104 port->io = pci_resource_start(pci, 0);
105
106 gp->gameport = port;
107 gp->res_port = request_region(port->io, 0x10, "FM801 GP");
108 if (!gp->res_port) {
109 kfree(gp);
110 gameport_free_port(port);
111 printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
112 port->io, port->io + 0x0f);
113 return -EBUSY;
114 }
115
116 pci_set_drvdata(pci, gp);
117
118 outb(0x60, port->io + 0x0d); /* enable joystick 1 and 2 */
119 gameport_register_port(port);
120
121 return 0;
122}
123
124static void __devexit fm801_gp_remove(struct pci_dev *pci)
125{
126 struct fm801_gp *gp = pci_get_drvdata(pci);
127
128 if (gp) {
129 gameport_unregister_port(gp->gameport);
130 release_resource(gp->res_port);
131 kfree(gp);
132 }
133}
134
135static struct pci_device_id fm801_gp_id_table[] = {
136 { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
137 { 0 }
138};
139
140static struct pci_driver fm801_gp_driver = {
141 .name = "FM801_gameport",
142 .id_table = fm801_gp_id_table,
143 .probe = fm801_gp_probe,
144 .remove = __devexit_p(fm801_gp_remove),
145};
146
147static int __init fm801_gp_init(void)
148{
149 return pci_register_driver(&fm801_gp_driver);
150}
151
152static void __exit fm801_gp_exit(void)
153{
154 pci_unregister_driver(&fm801_gp_driver);
155}
156
157module_init(fm801_gp_init);
158module_exit(fm801_gp_exit);
159
160MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
161
162MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
163MODULE_LICENSE("GPL");
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
new file mode 100644
index 000000000000..f20c3f23388b
--- /dev/null
+++ b/drivers/input/gameport/gameport.c
@@ -0,0 +1,797 @@
1/*
2 * Generic gameport layer
3 *
4 * Copyright (c) 1999-2002 Vojtech Pavlik
5 * Copyright (c) 2005 Dmitry Torokhov
6 */
7
8/*
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 */
13
14#include <linux/stddef.h>
15#include <linux/module.h>
16#include <linux/ioport.h>
17#include <linux/init.h>
18#include <linux/gameport.h>
19#include <linux/wait.h>
20#include <linux/completion.h>
21#include <linux/sched.h>
22#include <linux/smp_lock.h>
23#include <linux/slab.h>
24#include <linux/delay.h>
25
26/*#include <asm/io.h>*/
27
28MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
29MODULE_DESCRIPTION("Generic gameport layer");
30MODULE_LICENSE("GPL");
31
32EXPORT_SYMBOL(__gameport_register_port);
33EXPORT_SYMBOL(gameport_unregister_port);
34EXPORT_SYMBOL(__gameport_register_driver);
35EXPORT_SYMBOL(gameport_unregister_driver);
36EXPORT_SYMBOL(gameport_open);
37EXPORT_SYMBOL(gameport_close);
38EXPORT_SYMBOL(gameport_rescan);
39EXPORT_SYMBOL(gameport_cooked_read);
40EXPORT_SYMBOL(gameport_set_name);
41EXPORT_SYMBOL(gameport_set_phys);
42EXPORT_SYMBOL(gameport_start_polling);
43EXPORT_SYMBOL(gameport_stop_polling);
44
45/*
46 * gameport_sem protects entire gameport subsystem and is taken
47 * every time gameport port or driver registrered or unregistered.
48 */
49static DECLARE_MUTEX(gameport_sem);
50
51static LIST_HEAD(gameport_list);
52
53static struct bus_type gameport_bus = {
54 .name = "gameport",
55};
56
57static void gameport_add_port(struct gameport *gameport);
58static void gameport_destroy_port(struct gameport *gameport);
59static void gameport_reconnect_port(struct gameport *gameport);
60static void gameport_disconnect_port(struct gameport *gameport);
61
62#if defined(__i386__)
63
64#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
65#define GET_TIME(x) do { x = get_time_pit(); } while (0)
66
67static unsigned int get_time_pit(void)
68{
69 extern spinlock_t i8253_lock;
70 unsigned long flags;
71 unsigned int count;
72
73 spin_lock_irqsave(&i8253_lock, flags);
74 outb_p(0x00, 0x43);
75 count = inb_p(0x40);
76 count |= inb_p(0x40) << 8;
77 spin_unlock_irqrestore(&i8253_lock, flags);
78
79 return count;
80}
81
82#endif
83
84
85
86/*
87 * gameport_measure_speed() measures the gameport i/o speed.
88 */
89
90static int gameport_measure_speed(struct gameport *gameport)
91{
92#if defined(__i386__)
93
94 unsigned int i, t, t1, t2, t3, tx;
95 unsigned long flags;
96
97 if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
98 return 0;
99
100 tx = 1 << 30;
101
102 for(i = 0; i < 50; i++) {
103 local_irq_save(flags);
104 GET_TIME(t1);
105 for (t = 0; t < 50; t++) gameport_read(gameport);
106 GET_TIME(t2);
107 GET_TIME(t3);
108 local_irq_restore(flags);
109 udelay(i * 10);
110 if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
111 }
112
113 gameport_close(gameport);
114 return 59659 / (tx < 1 ? 1 : tx);
115
116#elif defined (__x86_64__)
117
118 unsigned int i, t;
119 unsigned long tx, t1, t2, flags;
120
121 if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
122 return 0;
123
124 tx = 1 << 30;
125
126 for(i = 0; i < 50; i++) {
127 local_irq_save(flags);
128 rdtscl(t1);
129 for (t = 0; t < 50; t++) gameport_read(gameport);
130 rdtscl(t2);
131 local_irq_restore(flags);
132 udelay(i * 10);
133 if (t2 - t1 < tx) tx = t2 - t1;
134 }
135
136 gameport_close(gameport);
137 return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
138
139#else
140
141 unsigned int j, t = 0;
142
143 if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
144 return 0;
145
146 j = jiffies; while (j == jiffies);
147 j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
148
149 gameport_close(gameport);
150 return t * HZ / 1000;
151
152#endif
153}
154
155void gameport_start_polling(struct gameport *gameport)
156{
157 spin_lock(&gameport->timer_lock);
158
159 if (!gameport->poll_cnt++) {
160 BUG_ON(!gameport->poll_handler);
161 BUG_ON(!gameport->poll_interval);
162 mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
163 }
164
165 spin_unlock(&gameport->timer_lock);
166}
167
168void gameport_stop_polling(struct gameport *gameport)
169{
170 spin_lock(&gameport->timer_lock);
171
172 if (!--gameport->poll_cnt)
173 del_timer(&gameport->poll_timer);
174
175 spin_unlock(&gameport->timer_lock);
176}
177
178static void gameport_run_poll_handler(unsigned long d)
179{
180 struct gameport *gameport = (struct gameport *)d;
181
182 gameport->poll_handler(gameport);
183 if (gameport->poll_cnt)
184 mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
185}
186
187/*
188 * Basic gameport -> driver core mappings
189 */
190
191static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
192{
193 down_write(&gameport_bus.subsys.rwsem);
194
195 gameport->dev.driver = &drv->driver;
196 if (drv->connect(gameport, drv)) {
197 gameport->dev.driver = NULL;
198 goto out;
199 }
200 device_bind_driver(&gameport->dev);
201out:
202 up_write(&gameport_bus.subsys.rwsem);
203}
204
205static void gameport_release_driver(struct gameport *gameport)
206{
207 down_write(&gameport_bus.subsys.rwsem);
208 device_release_driver(&gameport->dev);
209 up_write(&gameport_bus.subsys.rwsem);
210}
211
212static void gameport_find_driver(struct gameport *gameport)
213{
214 down_write(&gameport_bus.subsys.rwsem);
215 device_attach(&gameport->dev);
216 up_write(&gameport_bus.subsys.rwsem);
217}
218
219
220/*
221 * Gameport event processing.
222 */
223
224enum gameport_event_type {
225 GAMEPORT_RESCAN,
226 GAMEPORT_RECONNECT,
227 GAMEPORT_REGISTER_PORT,
228 GAMEPORT_REGISTER_DRIVER,
229};
230
231struct gameport_event {
232 enum gameport_event_type type;
233 void *object;
234 struct module *owner;
235 struct list_head node;
236};
237
238static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
239static LIST_HEAD(gameport_event_list);
240static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
241static DECLARE_COMPLETION(gameport_exited);
242static int gameport_pid;
243
244static void gameport_queue_event(void *object, struct module *owner,
245 enum gameport_event_type event_type)
246{
247 unsigned long flags;
248 struct gameport_event *event;
249
250 spin_lock_irqsave(&gameport_event_lock, flags);
251
252 /*
253 * Scan event list for the other events for the same gameport port,
254 * starting with the most recent one. If event is the same we
255 * do not need add new one. If event is of different type we
256 * need to add this event and should not look further because
257 * we need to preseve sequence of distinct events.
258 */
259 list_for_each_entry_reverse(event, &gameport_event_list, node) {
260 if (event->object == object) {
261 if (event->type == event_type)
262 goto out;
263 break;
264 }
265 }
266
267 if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
268 if (!try_module_get(owner)) {
269 printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
270 goto out;
271 }
272
273 event->type = event_type;
274 event->object = object;
275 event->owner = owner;
276
277 list_add_tail(&event->node, &gameport_event_list);
278 wake_up(&gameport_wait);
279 } else {
280 printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);
281 }
282out:
283 spin_unlock_irqrestore(&gameport_event_lock, flags);
284}
285
286static void gameport_free_event(struct gameport_event *event)
287{
288 module_put(event->owner);
289 kfree(event);
290}
291
292static void gameport_remove_duplicate_events(struct gameport_event *event)
293{
294 struct list_head *node, *next;
295 struct gameport_event *e;
296 unsigned long flags;
297
298 spin_lock_irqsave(&gameport_event_lock, flags);
299
300 list_for_each_safe(node, next, &gameport_event_list) {
301 e = list_entry(node, struct gameport_event, node);
302 if (event->object == e->object) {
303 /*
304 * If this event is of different type we should not
305 * look further - we only suppress duplicate events
306 * that were sent back-to-back.
307 */
308 if (event->type != e->type)
309 break;
310
311 list_del_init(node);
312 gameport_free_event(e);
313 }
314 }
315
316 spin_unlock_irqrestore(&gameport_event_lock, flags);
317}
318
319
320static struct gameport_event *gameport_get_event(void)
321{
322 struct gameport_event *event;
323 struct list_head *node;
324 unsigned long flags;
325
326 spin_lock_irqsave(&gameport_event_lock, flags);
327
328 if (list_empty(&gameport_event_list)) {
329 spin_unlock_irqrestore(&gameport_event_lock, flags);
330 return NULL;
331 }
332
333 node = gameport_event_list.next;
334 event = list_entry(node, struct gameport_event, node);
335 list_del_init(node);
336
337 spin_unlock_irqrestore(&gameport_event_lock, flags);
338
339 return event;
340}
341
342static void gameport_handle_events(void)
343{
344 struct gameport_event *event;
345 struct gameport_driver *gameport_drv;
346
347 down(&gameport_sem);
348
349 while ((event = gameport_get_event())) {
350
351 switch (event->type) {
352 case GAMEPORT_REGISTER_PORT:
353 gameport_add_port(event->object);
354 break;
355
356 case GAMEPORT_RECONNECT:
357 gameport_reconnect_port(event->object);
358 break;
359
360 case GAMEPORT_RESCAN:
361 gameport_disconnect_port(event->object);
362 gameport_find_driver(event->object);
363 break;
364
365 case GAMEPORT_REGISTER_DRIVER:
366 gameport_drv = event->object;
367 driver_register(&gameport_drv->driver);
368 break;
369
370 default:
371 break;
372 }
373
374 gameport_remove_duplicate_events(event);
375 gameport_free_event(event);
376 }
377
378 up(&gameport_sem);
379}
380
381/*
382 * Remove all events that have been submitted for a given gameport port.
383 */
384static void gameport_remove_pending_events(struct gameport *gameport)
385{
386 struct list_head *node, *next;
387 struct gameport_event *event;
388 unsigned long flags;
389
390 spin_lock_irqsave(&gameport_event_lock, flags);
391
392 list_for_each_safe(node, next, &gameport_event_list) {
393 event = list_entry(node, struct gameport_event, node);
394 if (event->object == gameport) {
395 list_del_init(node);
396 gameport_free_event(event);
397 }
398 }
399
400 spin_unlock_irqrestore(&gameport_event_lock, flags);
401}
402
403/*
404 * Destroy child gameport port (if any) that has not been fully registered yet.
405 *
406 * Note that we rely on the fact that port can have only one child and therefore
407 * only one child registration request can be pending. Additionally, children
408 * are registered by driver's connect() handler so there can't be a grandchild
409 * pending registration together with a child.
410 */
411static struct gameport *gameport_get_pending_child(struct gameport *parent)
412{
413 struct gameport_event *event;
414 struct gameport *gameport, *child = NULL;
415 unsigned long flags;
416
417 spin_lock_irqsave(&gameport_event_lock, flags);
418
419 list_for_each_entry(event, &gameport_event_list, node) {
420 if (event->type == GAMEPORT_REGISTER_PORT) {
421 gameport = event->object;
422 if (gameport->parent == parent) {
423 child = gameport;
424 break;
425 }
426 }
427 }
428
429 spin_unlock_irqrestore(&gameport_event_lock, flags);
430 return child;
431}
432
433static int gameport_thread(void *nothing)
434{
435 lock_kernel();
436 daemonize("kgameportd");
437 allow_signal(SIGTERM);
438
439 do {
440 gameport_handle_events();
441 wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
442 try_to_freeze(PF_FREEZE);
443 } while (!signal_pending(current));
444
445 printk(KERN_DEBUG "gameport: kgameportd exiting\n");
446
447 unlock_kernel();
448 complete_and_exit(&gameport_exited, 0);
449}
450
451
452/*
453 * Gameport port operations
454 */
455
456static ssize_t gameport_show_description(struct device *dev, char *buf)
457{
458 struct gameport *gameport = to_gameport_port(dev);
459 return sprintf(buf, "%s\n", gameport->name);
460}
461
462static ssize_t gameport_rebind_driver(struct device *dev, const char *buf, size_t count)
463{
464 struct gameport *gameport = to_gameport_port(dev);
465 struct device_driver *drv;
466 int retval;
467
468 retval = down_interruptible(&gameport_sem);
469 if (retval)
470 return retval;
471
472 retval = count;
473 if (!strncmp(buf, "none", count)) {
474 gameport_disconnect_port(gameport);
475 } else if (!strncmp(buf, "reconnect", count)) {
476 gameport_reconnect_port(gameport);
477 } else if (!strncmp(buf, "rescan", count)) {
478 gameport_disconnect_port(gameport);
479 gameport_find_driver(gameport);
480 } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
481 gameport_disconnect_port(gameport);
482 gameport_bind_driver(gameport, to_gameport_driver(drv));
483 put_driver(drv);
484 } else {
485 retval = -EINVAL;
486 }
487
488 up(&gameport_sem);
489
490 return retval;
491}
492
493static struct device_attribute gameport_device_attrs[] = {
494 __ATTR(description, S_IRUGO, gameport_show_description, NULL),
495 __ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),
496 __ATTR_NULL
497};
498
499static void gameport_release_port(struct device *dev)
500{
501 struct gameport *gameport = to_gameport_port(dev);
502
503 kfree(gameport);
504 module_put(THIS_MODULE);
505}
506
507void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
508{
509 va_list args;
510
511 va_start(args, fmt);
512 vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);
513 va_end(args);
514}
515
516/*
517 * Prepare gameport port for registration.
518 */
519static void gameport_init_port(struct gameport *gameport)
520{
521 static atomic_t gameport_no = ATOMIC_INIT(0);
522
523 __module_get(THIS_MODULE);
524
525 init_MUTEX(&gameport->drv_sem);
526 device_initialize(&gameport->dev);
527 snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
528 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
529 gameport->dev.bus = &gameport_bus;
530 gameport->dev.release = gameport_release_port;
531 if (gameport->parent)
532 gameport->dev.parent = &gameport->parent->dev;
533
534 spin_lock_init(&gameport->timer_lock);
535 init_timer(&gameport->poll_timer);
536 gameport->poll_timer.function = gameport_run_poll_handler;
537 gameport->poll_timer.data = (unsigned long)gameport;
538}
539
540/*
541 * Complete gameport port registration.
542 * Driver core will attempt to find appropriate driver for the port.
543 */
544static void gameport_add_port(struct gameport *gameport)
545{
546 if (gameport->parent)
547 gameport->parent->child = gameport;
548
549 gameport->speed = gameport_measure_speed(gameport);
550
551 list_add_tail(&gameport->node, &gameport_list);
552
553 if (gameport->io)
554 printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
555 gameport->name, gameport->phys, gameport->io, gameport->speed);
556 else
557 printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
558 gameport->name, gameport->phys, gameport->speed);
559
560 device_add(&gameport->dev);
561 gameport->registered = 1;
562}
563
564/*
565 * gameport_destroy_port() completes deregistration process and removes
566 * port from the system
567 */
568static void gameport_destroy_port(struct gameport *gameport)
569{
570 struct gameport *child;
571
572 child = gameport_get_pending_child(gameport);
573 if (child) {
574 gameport_remove_pending_events(child);
575 put_device(&child->dev);
576 }
577
578 if (gameport->parent) {
579 gameport->parent->child = NULL;
580 gameport->parent = NULL;
581 }
582
583 if (gameport->registered) {
584 device_del(&gameport->dev);
585 list_del_init(&gameport->node);
586 gameport->registered = 0;
587 }
588
589 gameport_remove_pending_events(gameport);
590 put_device(&gameport->dev);
591}
592
593/*
594 * Reconnect gameport port and all its children (re-initialize attached devices)
595 */
596static void gameport_reconnect_port(struct gameport *gameport)
597{
598 do {
599 if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {
600 gameport_disconnect_port(gameport);
601 gameport_find_driver(gameport);
602 /* Ok, old children are now gone, we are done */
603 break;
604 }
605 gameport = gameport->child;
606 } while (gameport);
607}
608
609/*
610 * gameport_disconnect_port() unbinds a port from its driver. As a side effect
611 * all child ports are unbound and destroyed.
612 */
613static void gameport_disconnect_port(struct gameport *gameport)
614{
615 struct gameport *s, *parent;
616
617 if (gameport->child) {
618 /*
619 * Children ports should be disconnected and destroyed
620 * first, staring with the leaf one, since we don't want
621 * to do recursion
622 */
623 for (s = gameport; s->child; s = s->child)
624 /* empty */;
625
626 do {
627 parent = s->parent;
628
629 gameport_release_driver(s);
630 gameport_destroy_port(s);
631 } while ((s = parent) != gameport);
632 }
633
634 /*
635 * Ok, no children left, now disconnect this port
636 */
637 gameport_release_driver(gameport);
638}
639
640void gameport_rescan(struct gameport *gameport)
641{
642 gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN);
643}
644
645void gameport_reconnect(struct gameport *gameport)
646{
647 gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT);
648}
649
650/*
651 * Submits register request to kgameportd for subsequent execution.
652 * Note that port registration is always asynchronous.
653 */
654void __gameport_register_port(struct gameport *gameport, struct module *owner)
655{
656 gameport_init_port(gameport);
657 gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);
658}
659
660/*
661 * Synchronously unregisters gameport port.
662 */
663void gameport_unregister_port(struct gameport *gameport)
664{
665 down(&gameport_sem);
666 gameport_disconnect_port(gameport);
667 gameport_destroy_port(gameport);
668 up(&gameport_sem);
669}
670
671
672/*
673 * Gameport driver operations
674 */
675
676static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)
677{
678 struct gameport_driver *driver = to_gameport_driver(drv);
679 return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
680}
681
682static struct driver_attribute gameport_driver_attrs[] = {
683 __ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),
684 __ATTR_NULL
685};
686
687static int gameport_driver_probe(struct device *dev)
688{
689 struct gameport *gameport = to_gameport_port(dev);
690 struct gameport_driver *drv = to_gameport_driver(dev->driver);
691
692 drv->connect(gameport, drv);
693 return gameport->drv ? 0 : -ENODEV;
694}
695
696static int gameport_driver_remove(struct device *dev)
697{
698 struct gameport *gameport = to_gameport_port(dev);
699 struct gameport_driver *drv = to_gameport_driver(dev->driver);
700
701 drv->disconnect(gameport);
702 return 0;
703}
704
705void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
706{
707 drv->driver.bus = &gameport_bus;
708 drv->driver.probe = gameport_driver_probe;
709 drv->driver.remove = gameport_driver_remove;
710 gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
711}
712
713void gameport_unregister_driver(struct gameport_driver *drv)
714{
715 struct gameport *gameport;
716
717 down(&gameport_sem);
718 drv->ignore = 1; /* so gameport_find_driver ignores it */
719
720start_over:
721 list_for_each_entry(gameport, &gameport_list, node) {
722 if (gameport->drv == drv) {
723 gameport_disconnect_port(gameport);
724 gameport_find_driver(gameport);
725 /* we could've deleted some ports, restart */
726 goto start_over;
727 }
728 }
729
730 driver_unregister(&drv->driver);
731 up(&gameport_sem);
732}
733
734static int gameport_bus_match(struct device *dev, struct device_driver *drv)
735{
736 struct gameport_driver *gameport_drv = to_gameport_driver(drv);
737
738 return !gameport_drv->ignore;
739}
740
741static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
742{
743 down(&gameport->drv_sem);
744 gameport->drv = drv;
745 up(&gameport->drv_sem);
746}
747
748int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
749{
750
751 if (gameport->open) {
752 if (gameport->open(gameport, mode)) {
753 return -1;
754 }
755 } else {
756 if (mode != GAMEPORT_MODE_RAW)
757 return -1;
758 }
759
760 gameport_set_drv(gameport, drv);
761 return 0;
762}
763
764void gameport_close(struct gameport *gameport)
765{
766 del_timer_sync(&gameport->poll_timer);
767 gameport->poll_handler = NULL;
768 gameport->poll_interval = 0;
769 gameport_set_drv(gameport, NULL);
770 if (gameport->close)
771 gameport->close(gameport);
772}
773
774static int __init gameport_init(void)
775{
776 if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
777 printk(KERN_ERR "gameport: Failed to start kgameportd\n");
778 return -1;
779 }
780
781 gameport_bus.dev_attrs = gameport_device_attrs;
782 gameport_bus.drv_attrs = gameport_driver_attrs;
783 gameport_bus.match = gameport_bus_match;
784 bus_register(&gameport_bus);
785
786 return 0;
787}
788
789static void __exit gameport_exit(void)
790{
791 bus_unregister(&gameport_bus);
792 kill_proc(gameport_pid, SIGTERM, 1);
793 wait_for_completion(&gameport_exited);
794}
795
796module_init(gameport_init);
797module_exit(gameport_exit);
diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
new file mode 100644
index 000000000000..d65d81080257
--- /dev/null
+++ b/drivers/input/gameport/lightning.c
@@ -0,0 +1,344 @@
1/*
2 * $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech Exp $
3 *
4 * Copyright (c) 1998-2001 Vojtech Pavlik
5 */
6
7/*
8 * PDPI Lightning 4 gamecard driver for Linux.
9 */
10
11/*
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
28 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
29 */
30
31#include <asm/io.h>
32#include <linux/delay.h>
33#include <linux/errno.h>
34#include <linux/ioport.h>
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/init.h>
38#include <linux/gameport.h>
39#include <linux/slab.h>
40
41#define L4_PORT 0x201
42#define L4_SELECT_ANALOG 0xa4
43#define L4_SELECT_DIGITAL 0xa5
44#define L4_SELECT_SECONDARY 0xa6
45#define L4_CMD_ID 0x80
46#define L4_CMD_GETCAL 0x92
47#define L4_CMD_SETCAL 0x93
48#define L4_ID 0x04
49#define L4_BUSY 0x01
50#define L4_TIMEOUT 80 /* 80 us */
51
52MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
53MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
54MODULE_LICENSE("GPL");
55
56struct l4 {
57 struct gameport *gameport;
58 unsigned char port;
59};
60
61static struct l4 l4_ports[8];
62
63/*
64 * l4_wait_ready() waits for the L4 to become ready.
65 */
66
67static int l4_wait_ready(void)
68{
69 unsigned int t = L4_TIMEOUT;
70
71 while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
72 return -(t <= 0);
73}
74
75/*
76 * l4_cooked_read() reads data from the Lightning 4.
77 */
78
79static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
80{
81 struct l4 *l4 = gameport->port_data;
82 unsigned char status;
83 int i, result = -1;
84
85 outb(L4_SELECT_ANALOG, L4_PORT);
86 outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
87
88 if (inb(L4_PORT) & L4_BUSY) goto fail;
89 outb(l4->port & 3, L4_PORT);
90
91 if (l4_wait_ready()) goto fail;
92 status = inb(L4_PORT);
93
94 for (i = 0; i < 4; i++)
95 if (status & (1 << i)) {
96 if (l4_wait_ready()) goto fail;
97 axes[i] = inb(L4_PORT);
98 if (axes[i] > 252) axes[i] = -1;
99 }
100
101 if (status & 0x10) {
102 if (l4_wait_ready()) goto fail;
103 *buttons = inb(L4_PORT) & 0x0f;
104 }
105
106 result = 0;
107
108fail: outb(L4_SELECT_ANALOG, L4_PORT);
109 return result;
110}
111
112static int l4_open(struct gameport *gameport, int mode)
113{
114 struct l4 *l4 = gameport->port_data;
115
116 if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
117 return -1;
118 outb(L4_SELECT_ANALOG, L4_PORT);
119 return 0;
120}
121
122/*
123 * l4_getcal() reads the L4 with calibration values.
124 */
125
126static int l4_getcal(int port, int *cal)
127{
128 int i, result = -1;
129
130 outb(L4_SELECT_ANALOG, L4_PORT);
131 outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
132 if (inb(L4_PORT) & L4_BUSY)
133 goto out;
134
135 outb(L4_CMD_GETCAL, L4_PORT);
136 if (l4_wait_ready())
137 goto out;
138
139 if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
140 goto out;
141
142 if (l4_wait_ready())
143 goto out;
144 outb(port & 3, L4_PORT);
145
146 for (i = 0; i < 4; i++) {
147 if (l4_wait_ready())
148 goto out;
149 cal[i] = inb(L4_PORT);
150 }
151
152 result = 0;
153
154out: outb(L4_SELECT_ANALOG, L4_PORT);
155 return result;
156}
157
158/*
159 * l4_setcal() programs the L4 with calibration values.
160 */
161
162static int l4_setcal(int port, int *cal)
163{
164 int i, result = -1;
165
166 outb(L4_SELECT_ANALOG, L4_PORT);
167 outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
168 if (inb(L4_PORT) & L4_BUSY)
169 goto out;
170
171 outb(L4_CMD_SETCAL, L4_PORT);
172 if (l4_wait_ready())
173 goto out;
174
175 if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
176 goto out;
177
178 if (l4_wait_ready())
179 goto out;
180 outb(port & 3, L4_PORT);
181
182 for (i = 0; i < 4; i++) {
183 if (l4_wait_ready())
184 goto out;
185 outb(cal[i], L4_PORT);
186 }
187
188 result = 0;
189
190out: outb(L4_SELECT_ANALOG, L4_PORT);
191 return result;
192}
193
194/*
195 * l4_calibrate() calibrates the L4 for the attached device, so
196 * that the device's resistance fits into the L4's 8-bit range.
197 */
198
199static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
200{
201 int i, t;
202 int cal[4];
203 struct l4 *l4 = gameport->port_data;
204
205 if (l4_getcal(l4->port, cal))
206 return -1;
207
208 for (i = 0; i < 4; i++) {
209 t = (max[i] * cal[i]) / 200;
210 t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
211 axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
212 axes[i] = (axes[i] > 252) ? 252 : axes[i];
213 cal[i] = t;
214 }
215
216 if (l4_setcal(l4->port, cal))
217 return -1;
218
219 return 0;
220}
221
222static int __init l4_create_ports(int card_no)
223{
224 struct l4 *l4;
225 struct gameport *port;
226 int i, idx;
227
228 for (i = 0; i < 4; i++) {
229
230 idx = card_no * 4 + i;
231 l4 = &l4_ports[idx];
232
233 if (!(l4->gameport = port = gameport_allocate_port())) {
234 printk(KERN_ERR "lightning: Memory allocation failed\n");
235 while (--i >= 0) {
236 gameport_free_port(l4->gameport);
237 l4->gameport = NULL;
238 }
239 return -ENOMEM;
240 }
241 l4->port = idx;
242
243 port->port_data = l4;
244 port->open = l4_open;
245 port->cooked_read = l4_cooked_read;
246 port->calibrate = l4_calibrate;
247
248 gameport_set_name(port, "PDPI Lightning 4");
249 gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
250
251 if (idx == 0)
252 port->io = L4_PORT;
253 }
254
255 return 0;
256}
257
258static int __init l4_add_card(int card_no)
259{
260 int cal[4] = { 255, 255, 255, 255 };
261 int i, rev, result;
262 struct l4 *l4;
263
264 outb(L4_SELECT_ANALOG, L4_PORT);
265 outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
266
267 if (inb(L4_PORT) & L4_BUSY)
268 return -1;
269 outb(L4_CMD_ID, L4_PORT);
270
271 if (l4_wait_ready())
272 return -1;
273
274 if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
275 return -1;
276
277 if (l4_wait_ready())
278 return -1;
279 if (inb(L4_PORT) != L4_ID)
280 return -1;
281
282 if (l4_wait_ready())
283 return -1;
284 rev = inb(L4_PORT);
285
286 if (!rev)
287 return -1;
288
289 result = l4_create_ports(card_no);
290 if (result)
291 return result;
292
293 printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
294 card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
295
296 for (i = 0; i < 4; i++) {
297 l4 = &l4_ports[card_no * 4 + i];
298
299 if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
300 l4_setcal(l4->port, cal);
301 gameport_register_port(l4->gameport);
302 }
303
304 return 0;
305}
306
307static int __init l4_init(void)
308{
309 int i, cards = 0;
310
311 if (!request_region(L4_PORT, 1, "lightning"))
312 return -1;
313
314 for (i = 0; i < 2; i++)
315 if (l4_add_card(i) == 0)
316 cards++;
317
318 outb(L4_SELECT_ANALOG, L4_PORT);
319
320 if (!cards) {
321 release_region(L4_PORT, 1);
322 return -1;
323 }
324
325 return 0;
326}
327
328static void __exit l4_exit(void)
329{
330 int i;
331 int cal[4] = { 59, 59, 59, 59 };
332
333 for (i = 0; i < 8; i++)
334 if (l4_ports[i].gameport) {
335 l4_setcal(l4_ports[i].port, cal);
336 gameport_unregister_port(l4_ports[i].gameport);
337 }
338
339 outb(L4_SELECT_ANALOG, L4_PORT);
340 release_region(L4_PORT, 1);
341}
342
343module_init(l4_init);
344module_exit(l4_exit);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
new file mode 100644
index 000000000000..7c5c6318eeb9
--- /dev/null
+++ b/drivers/input/gameport/ns558.c
@@ -0,0 +1,291 @@
1/*
2 * $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $
3 *
4 * Copyright (c) 1999-2001 Vojtech Pavlik
5 * Copyright (c) 1999 Brian Gerst
6 */
7
8/*
9 * NS558 based standard IBM game port driver for Linux
10 */
11
12/*
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 * Should you need to contact me, the author, you can do so either by
28 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
29 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
30 */
31
32#include <asm/io.h>
33
34#include <linux/module.h>
35#include <linux/ioport.h>
36#include <linux/config.h>
37#include <linux/init.h>
38#include <linux/delay.h>
39#include <linux/gameport.h>
40#include <linux/slab.h>
41#include <linux/pnp.h>
42
43MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
44MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
45MODULE_LICENSE("GPL");
46
47static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
48 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
49
50struct ns558 {
51 int type;
52 int io;
53 int size;
54 struct pnp_dev *dev;
55 struct gameport *gameport;
56 struct list_head node;
57};
58
59static LIST_HEAD(ns558_list);
60
61/*
62 * ns558_isa_probe() tries to find an isa gameport at the
63 * specified address, and also checks for mirrors.
64 * A joystick must be attached for this to work.
65 */
66
67static int ns558_isa_probe(int io)
68{
69 int i, j, b;
70 unsigned char c, u, v;
71 struct ns558 *ns558;
72 struct gameport *port;
73
74/*
75 * No one should be using this address.
76 */
77
78 if (!request_region(io, 1, "ns558-isa"))
79 return -EBUSY;
80
81/*
82 * We must not be able to write arbitrary values to the port.
83 * The lower two axis bits must be 1 after a write.
84 */
85
86 c = inb(io);
87 outb(~c & ~3, io);
88 if (~(u = v = inb(io)) & 3) {
89 outb(c, io);
90 release_region(io, 1);
91 return -ENODEV;
92 }
93/*
94 * After a trigger, there must be at least some bits changing.
95 */
96
97 for (i = 0; i < 1000; i++) v &= inb(io);
98
99 if (u == v) {
100 outb(c, io);
101 release_region(io, 1);
102 return -ENODEV;
103 }
104 msleep(3);
105/*
106 * After some time (4ms) the axes shouldn't change anymore.
107 */
108
109 u = inb(io);
110 for (i = 0; i < 1000; i++)
111 if ((u ^ inb(io)) & 0xf) {
112 outb(c, io);
113 release_region(io, 1);
114 return -ENODEV;
115 }
116/*
117 * And now find the number of mirrors of the port.
118 */
119
120 for (i = 1; i < 5; i++) {
121
122 release_region(io & (-1 << (i - 1)), (1 << (i - 1)));
123
124 if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
125 break; /* Don't disturb anyone */
126
127 outb(0xff, io & (-1 << i));
128 for (j = b = 0; j < 1000; j++)
129 if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
130 msleep(3);
131
132 if (b > 300) { /* We allow 30% difference */
133 release_region(io & (-1 << i), (1 << i));
134 break;
135 }
136 }
137
138 i--;
139
140 if (i != 4) {
141 if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
142 return -EBUSY;
143 }
144
145 ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
146 port = gameport_allocate_port();
147 if (!ns558 || !port) {
148 printk(KERN_ERR "ns558: Memory allocation failed.\n");
149 release_region(io & (-1 << i), (1 << i));
150 kfree(ns558);
151 gameport_free_port(port);
152 return -ENOMEM;
153 }
154
155 memset(ns558, 0, sizeof(struct ns558));
156 ns558->io = io;
157 ns558->size = 1 << i;
158 ns558->gameport = port;
159
160 port->io = io;
161 gameport_set_name(port, "NS558 ISA Gameport");
162 gameport_set_phys(port, "isa%04x/gameport0", io & (-1 << i));
163
164 gameport_register_port(port);
165
166 list_add(&ns558->node, &ns558_list);
167
168 return 0;
169}
170
171#ifdef CONFIG_PNP
172
173static struct pnp_device_id pnp_devids[] = {
174 { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
175 { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
176 { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
177 { .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
178 { .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
179 { .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
180 { .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
181 { .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
182 { .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
183 { .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
184 { .id = "CTL7001", .driver_data = 0 }, /* SB16 */
185 { .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
186 { .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
187 { .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
188 { .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
189 { .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
190 { .id = "ESS6880", .driver_data = 0 }, /* ES688 */
191 { .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
192 { .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
193 { .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
194 { .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
195 { .id = "PNPb02f", .driver_data = 0 }, /* Generic */
196 { .id = "", },
197};
198
199MODULE_DEVICE_TABLE(pnp, pnp_devids);
200
201static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
202{
203 int ioport, iolen;
204 struct ns558 *ns558;
205 struct gameport *port;
206
207 if (!pnp_port_valid(dev, 0)) {
208 printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
209 return -ENODEV;
210 }
211
212 ioport = pnp_port_start(dev, 0);
213 iolen = pnp_port_len(dev, 0);
214
215 if (!request_region(ioport, iolen, "ns558-pnp"))
216 return -EBUSY;
217
218 ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
219 port = gameport_allocate_port();
220 if (!ns558 || !port) {
221 printk(KERN_ERR "ns558: Memory allocation failed\n");
222 kfree(ns558);
223 gameport_free_port(port);
224 return -ENOMEM;
225 }
226
227 ns558->io = ioport;
228 ns558->size = iolen;
229 ns558->dev = dev;
230 ns558->gameport = port;
231
232 gameport_set_name(port, "NS558 PnP Gameport");
233 gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id);
234 port->dev.parent = &dev->dev;
235 port->io = ioport;
236
237 gameport_register_port(port);
238
239 list_add_tail(&ns558->node, &ns558_list);
240 return 0;
241}
242
243static struct pnp_driver ns558_pnp_driver = {
244 .name = "ns558",
245 .id_table = pnp_devids,
246 .probe = ns558_pnp_probe,
247};
248
249#else
250
251static struct pnp_driver ns558_pnp_driver;
252
253#endif
254
255static int pnp_registered = 0;
256
257static int __init ns558_init(void)
258{
259 int i = 0;
260
261/*
262 * Probe ISA ports first so that PnP gets to choose free port addresses
263 * not occupied by the ISA ports.
264 */
265
266 while (ns558_isa_portlist[i])
267 ns558_isa_probe(ns558_isa_portlist[i++]);
268
269 if (pnp_register_driver(&ns558_pnp_driver) >= 0)
270 pnp_registered = 1;
271
272
273 return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
274}
275
276static void __exit ns558_exit(void)
277{
278 struct ns558 *ns558;
279
280 list_for_each_entry(ns558, &ns558_list, node) {
281 gameport_unregister_port(ns558->gameport);
282 release_region(ns558->io & ~(ns558->size - 1), ns558->size);
283 kfree(ns558);
284 }
285
286 if (pnp_registered)
287 pnp_unregister_driver(&ns558_pnp_driver);
288}
289
290module_init(ns558_init);
291module_exit(ns558_exit);
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
new file mode 100644
index 000000000000..36b0309c8bf6
--- /dev/null
+++ b/drivers/input/gameport/vortex.c
@@ -0,0 +1,186 @@
1/*
2 * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * Raymond Ingles
8 */
9
10/*
11 * Trident 4DWave and Aureal Vortex gameport driver for Linux
12 */
13
14/*
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 * Should you need to contact me, the author, you can do so either by
30 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
31 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
32 */
33
34#include <asm/io.h>
35#include <linux/delay.h>
36#include <linux/errno.h>
37#include <linux/ioport.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/pci.h>
41#include <linux/init.h>
42#include <linux/slab.h>
43#include <linux/delay.h>
44#include <linux/gameport.h>
45
46MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
47MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
48MODULE_LICENSE("GPL");
49
50#define VORTEX_GCR 0x0c /* Gameport control register */
51#define VORTEX_LEG 0x08 /* Legacy port location */
52#define VORTEX_AXD 0x10 /* Axes start */
53#define VORTEX_DATA_WAIT 20 /* 20 ms */
54
55struct vortex {
56 struct gameport *gameport;
57 struct pci_dev *dev;
58 unsigned char __iomem *base;
59 unsigned char __iomem *io;
60};
61
62static unsigned char vortex_read(struct gameport *gameport)
63{
64 struct vortex *vortex = gameport->port_data;
65 return readb(vortex->io + VORTEX_LEG);
66}
67
68static void vortex_trigger(struct gameport *gameport)
69{
70 struct vortex *vortex = gameport->port_data;
71 writeb(0xff, vortex->io + VORTEX_LEG);
72}
73
74static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
75{
76 struct vortex *vortex = gameport->port_data;
77 int i;
78
79 *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
80
81 for (i = 0; i < 4; i++) {
82 axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
83 if (axes[i] == 0x1fff) axes[i] = -1;
84 }
85
86 return 0;
87}
88
89static int vortex_open(struct gameport *gameport, int mode)
90{
91 struct vortex *vortex = gameport->port_data;
92
93 switch (mode) {
94 case GAMEPORT_MODE_COOKED:
95 writeb(0x40, vortex->io + VORTEX_GCR);
96 msleep(VORTEX_DATA_WAIT);
97 return 0;
98 case GAMEPORT_MODE_RAW:
99 writeb(0x00, vortex->io + VORTEX_GCR);
100 return 0;
101 default:
102 return -1;
103 }
104
105 return 0;
106}
107
108static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
109{
110 struct vortex *vortex;
111 struct gameport *port;
112 int i;
113
114 vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
115 port = gameport_allocate_port();
116 if (!vortex || !port) {
117 printk(KERN_ERR "vortex: Memory allocation failed.\n");
118 kfree(vortex);
119 gameport_free_port(port);
120 return -ENOMEM;
121 }
122
123 for (i = 0; i < 6; i++)
124 if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
125 break;
126
127 pci_enable_device(dev);
128
129 vortex->dev = dev;
130 vortex->gameport = port;
131 vortex->base = ioremap(pci_resource_start(vortex->dev, i),
132 pci_resource_len(vortex->dev, i));
133 vortex->io = vortex->base + id->driver_data;
134
135 pci_set_drvdata(dev, vortex);
136
137 port->port_data = vortex;
138 port->fuzz = 64;
139
140 gameport_set_name(port, "AU88x0");
141 gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
142 port->dev.parent = &dev->dev;
143 port->read = vortex_read;
144 port->trigger = vortex_trigger;
145 port->cooked_read = vortex_cooked_read;
146 port->open = vortex_open;
147
148 gameport_register_port(port);
149
150 return 0;
151}
152
153static void __devexit vortex_remove(struct pci_dev *dev)
154{
155 struct vortex *vortex = pci_get_drvdata(dev);
156
157 gameport_unregister_port(vortex->gameport);
158 iounmap(vortex->base);
159 kfree(vortex);
160}
161
162static struct pci_device_id vortex_id_table[] = {
163 { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
164 { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
165 { 0 }
166};
167
168static struct pci_driver vortex_driver = {
169 .name = "vortex_gameport",
170 .id_table = vortex_id_table,
171 .probe = vortex_probe,
172 .remove = __devexit_p(vortex_remove),
173};
174
175static int __init vortex_init(void)
176{
177 return pci_register_driver(&vortex_driver);
178}
179
180static void __exit vortex_exit(void)
181{
182 pci_unregister_driver(&vortex_driver);
183}
184
185module_init(vortex_init);
186module_exit(vortex_exit);