Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
494 giacomo 1
/*
2
 * Generic gameport layer
3
 *
4
 * Copyright (c) 1999-2002 Vojtech Pavlik
5
 */
6
 
7
/*
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU General Public License version 2 as published by
10
 * the Free Software Foundation.
11
 */
12
 
13
#include <linuxcomp.h>
14
 
15
#include <asm/io.h>
16
#include <linux/module.h>
17
#include <linux/ioport.h>
18
#include <linux/init.h>
19
#include <linux/gameport.h>
20
#include <linux/slab.h>
21
#include <linux/stddef.h>
22
#include <linux/delay.h>
23
 
24
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
25
MODULE_DESCRIPTION("Generic gameport layer");
26
MODULE_LICENSE("GPL");
27
 
28
EXPORT_SYMBOL(gameport_register_port);
29
EXPORT_SYMBOL(gameport_unregister_port);
30
EXPORT_SYMBOL(gameport_register_device);
31
EXPORT_SYMBOL(gameport_unregister_device);
32
EXPORT_SYMBOL(gameport_open);
33
EXPORT_SYMBOL(gameport_close);
34
EXPORT_SYMBOL(gameport_rescan);
35
EXPORT_SYMBOL(gameport_cooked_read);
36
 
37
static LIST_HEAD(gameport_list);
38
static LIST_HEAD(gameport_dev_list);
39
 
40
#ifdef __i386__
41
 
42
#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))
43
#define GET_TIME(x)     do { x = get_time_pit(); } while (0)
44
 
45
static unsigned int get_time_pit(void)
46
{
47
        extern spinlock_t i8253_lock;
48
        unsigned long flags;
49
        unsigned int count;
50
 
51
        spin_lock_irqsave(&i8253_lock, flags);
52
        outb_p(0x00, 0x43);
53
        count = inb_p(0x40);
54
        count |= inb_p(0x40) << 8;
55
        spin_unlock_irqrestore(&i8253_lock, flags);
56
 
57
        return count;
58
}
59
 
60
#endif
61
 
62
/*
63
 * gameport_measure_speed() measures the gameport i/o speed.
64
 */
65
 
66
static int gameport_measure_speed(struct gameport *gameport)
67
{
68
#ifdef __i386__
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
                local_irq_save(flags);
80
                GET_TIME(t1);
81
                for(t = 0; t < 50; t++) gameport_read(gameport);
82
                GET_TIME(t2);
83
                GET_TIME(t3);
84
                local_irq_restore(flags);
85
                udelay(i * 10);
86
                if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
87
        }
88
 
89
        gameport_close(gameport);
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
        gameport_close(gameport);
100
        return t * HZ / 1000;
101
 
102
#endif
103
}
104
 
105
static void gameport_find_dev(struct gameport *gameport)
106
{
107
        struct gameport_dev *dev;
108
 
109
        list_for_each_entry(dev, &gameport_dev_list, node) {
110
                if (gameport->dev)
111
                        break;
112
                if (dev->connect)
113
                        dev->connect(gameport, dev);
114
        }
115
}
116
 
117
void gameport_rescan(struct gameport *gameport)
118
{
119
        gameport_close(gameport);
120
        gameport_find_dev(gameport);
121
}
122
 
123
void gameport_register_port(struct gameport *gameport)
124
{
125
        list_add_tail(&gameport->node, &gameport_list);
126
        gameport->speed = gameport_measure_speed(gameport);
127
        gameport_find_dev(gameport);
128
}
129
 
130
void gameport_unregister_port(struct gameport *gameport)
131
{
132
        list_del_init(&gameport->node);
133
        if (gameport->dev && gameport->dev->disconnect)
134
                gameport->dev->disconnect(gameport);
135
}
136
 
137
void gameport_register_device(struct gameport_dev *dev)
138
{
139
        struct gameport *gameport;
140
 
141
        list_add_tail(&dev->node, &gameport_dev_list);
142
        list_for_each_entry(gameport, &gameport_list, node)
143
                if (!gameport->dev && dev->connect)
144
                        dev->connect(gameport, dev);
145
}
146
 
147
void gameport_unregister_device(struct gameport_dev *dev)
148
{
149
        struct gameport *gameport;
150
 
151
        list_del_init(&dev->node);
152
        list_for_each_entry(gameport, &gameport_list, node) {
153
                if (gameport->dev == dev && dev->disconnect)
154
                        dev->disconnect(gameport);
155
                gameport_find_dev(gameport);
156
        }
157
}
158
 
159
int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
160
{
161
        if (gameport->open) {
162
                if (gameport->open(gameport, mode))
163
                        return -1;
164
        } else {
165
                if (mode != GAMEPORT_MODE_RAW)
166
                        return -1;
167
        }
168
 
169
        if (gameport->dev)
170
                return -1;
171
 
172
        gameport->dev = dev;
173
 
174
        return 0;
175
}
176
 
177
void gameport_close(struct gameport *gameport)
178
{
179
        gameport->dev = NULL;
180
        if (gameport->close)
181
                gameport->close(gameport);
182
}