1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <asm/io.h>
34#include <linux/module.h>
35#include <linux/ioport.h>
36#include <linux/init.h>
37#include <linux/gameport.h>
38#include <linux/slab.h>
39#include <linux/isapnp.h>
40#include <linux/stddef.h>
41#include <linux/delay.h>
42
43MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
44MODULE_LICENSE("GPL");
45
46EXPORT_SYMBOL(gameport_register_port);
47EXPORT_SYMBOL(gameport_unregister_port);
48EXPORT_SYMBOL(gameport_register_device);
49EXPORT_SYMBOL(gameport_unregister_device);
50EXPORT_SYMBOL(gameport_open);
51EXPORT_SYMBOL(gameport_close);
52EXPORT_SYMBOL(gameport_rescan);
53EXPORT_SYMBOL(gameport_cooked_read);
54
55static struct gameport *gameport_list;
56static struct gameport_dev *gameport_dev;
57static int gameport_number;
58
59
60
61
62
63static int gameport_measure_speed(struct gameport *gameport)
64{
65#if defined(__i386__) || defined(__x86_64__)
66
67#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
68#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
69
70 unsigned int i, t, t1, t2, t3, tx;
71 unsigned long flags;
72
73 if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
74 return 0;
75
76 tx = 1 << 30;
77
78 for(i = 0; i < 50; i++) {
79 save_flags(flags);
80 cli();
81 GET_TIME(t1);
82 for(t = 0; t < 50; t++) gameport_read(gameport);
83 GET_TIME(t2);
84 GET_TIME(t3);
85 restore_flags(flags);
86 udelay(i * 10);
87 if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
88 }
89
90 return 59659 / (tx < 1 ? 1 : tx);
91
92#else
93
94 unsigned int j, t = 0;
95
96 j = jiffies; while (j == jiffies);
97 j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
98
99 return t * HZ / 1000;
100
101#endif
102
103 gameport_close(gameport);
104}
105
106static void gameport_find_dev(struct gameport *gameport)
107{
108 struct gameport_dev *dev = gameport_dev;
109
110 while (dev && !gameport->dev) {
111 if (dev->connect)
112 dev->connect(gameport, dev);
113 dev = dev->next;
114 }
115}
116
117void gameport_rescan(struct gameport *gameport)
118{
119 gameport_close(gameport);
120 gameport_find_dev(gameport);
121}
122
123void gameport_register_port(struct gameport *gameport)
124{
125 gameport->number = gameport_number++;
126 gameport->next = gameport_list;
127 gameport_list = gameport;
128
129 gameport->speed = gameport_measure_speed(gameport);
130
131 gameport_find_dev(gameport);
132}
133
134void gameport_unregister_port(struct gameport *gameport)
135{
136 struct gameport **gameportptr = &gameport_list;
137
138 while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
139 *gameportptr = (*gameportptr)->next;
140
141 if (gameport->dev && gameport->dev->disconnect)
142 gameport->dev->disconnect(gameport);
143
144 gameport_number--;
145}
146
147void gameport_register_device(struct gameport_dev *dev)
148{
149 struct gameport *gameport = gameport_list;
150
151 dev->next = gameport_dev;
152 gameport_dev = dev;
153
154 while (gameport) {
155 if (!gameport->dev && dev->connect)
156 dev->connect(gameport, dev);
157 gameport = gameport->next;
158 }
159}
160
161void gameport_unregister_device(struct gameport_dev *dev)
162{
163 struct gameport_dev **devptr = &gameport_dev;
164 struct gameport *gameport = gameport_list;
165
166 while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
167 *devptr = (*devptr)->next;
168
169 while (gameport) {
170 if (gameport->dev == dev && dev->disconnect)
171 dev->disconnect(gameport);
172 gameport_find_dev(gameport);
173 gameport = gameport->next;
174 }
175}
176
177int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
178{
179 if (gameport->open) {
180 if (gameport->open(gameport, mode))
181 return -1;
182 } else {
183 if (mode != GAMEPORT_MODE_RAW)
184 return -1;
185 }
186
187 if (gameport->dev)
188 return -1;
189
190 gameport->dev = dev;
191
192 return 0;
193}
194
195void gameport_close(struct gameport *gameport)
196{
197 gameport->dev = NULL;
198 if (gameport->close) gameport->close(gameport);
199}
200