OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [joystick/] [a3d.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * $Id: a3d.c,v 1.1.1.1 2004-04-15 02:03:23 phoenix Exp $
3
 *
4
 *  Copyright (c) 1998-2001 Vojtech Pavlik
5
 *
6
 *  Sponsored by SuSE
7
 */
8
 
9
/*
10
 * FP-Gaming Assasin 3D joystick driver for Linux
11
 */
12
 
13
/*
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
 *
28
 * Should you need to contact me, the author, you can do so either by
29
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
30
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
31
 */
32
 
33
#include <linux/kernel.h>
34
#include <linux/module.h>
35
#include <linux/slab.h>
36
#include <linux/init.h>
37
#include <linux/gameport.h>
38
#include <linux/input.h>
39
 
40
#define A3D_MAX_START           400     /* 400 us */ 
41
#define A3D_MAX_STROBE          60      /* 40 us */ 
42
#define A3D_DELAY_READ          3       /* 3 ms */
43
#define A3D_MAX_LENGTH          40      /* 40*3 bits */
44
#define A3D_REFRESH_TIME        HZ/50   /* 20 ms */
45
 
46
#define A3D_MODE_A3D            1       /* Assassin 3D */
47
#define A3D_MODE_PAN            2       /* Panther */
48
#define A3D_MODE_OEM            3       /* Panther OEM version */
49
#define A3D_MODE_PXL            4       /* Panther XL */
50
 
51
char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
52
                        "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
53
 
54
struct a3d {
55
        struct gameport *gameport;
56
        struct gameport adc;
57
        struct input_dev dev;
58
        struct timer_list timer;
59
        int axes[4];
60
        int buttons;
61
        int mode;
62
        int length;
63
        int used;
64
        int reads;
65
        int bads;
66
};
67
 
68
/*
69
 * a3d_read_packet() reads an Assassin 3D packet.
70
 */
71
 
72
static int a3d_read_packet(struct gameport *gameport, int length, char *data)
73
{
74
        unsigned long flags;
75
        unsigned char u, v;
76
        unsigned int t, s;
77
        int i;
78
 
79
        i = 0;
80
        t = gameport_time(gameport, A3D_MAX_START);
81
        s = gameport_time(gameport, A3D_MAX_STROBE);
82
 
83
        __save_flags(flags);
84
        __cli();
85
        gameport_trigger(gameport);
86
        v = gameport_read(gameport);
87
 
88
        while (t > 0 && i < length) {
89
                t--;
90
                u = v; v = gameport_read(gameport);
91
                if (~v & u & 0x10) {
92
                        data[i++] = v >> 5;
93
                        t = s;
94
                }
95
        }
96
 
97
        __restore_flags(flags);
98
 
99
        return i;
100
}
101
 
102
/*
103
 * a3d_csum() computes checksum of triplet packet
104
 */
105
 
106
static int a3d_csum(char *data, int count)
107
{
108
        int i, csum = 0;
109
        for (i = 0; i < count - 2; i++) csum += data[i];
110
        return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
111
}
112
 
113
static void a3d_read(struct a3d *a3d, unsigned char *data)
114
{
115
        struct input_dev *dev = &a3d->dev;
116
 
117
        switch (a3d->mode) {
118
 
119
                case A3D_MODE_A3D:
120
                case A3D_MODE_OEM:
121
                case A3D_MODE_PAN:
122
 
123
                        input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
124
                        input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
125
 
126
                        input_report_key(dev, BTN_RIGHT,  data[2] & 1);
127
                        input_report_key(dev, BTN_LEFT,   data[3] & 2);
128
                        input_report_key(dev, BTN_MIDDLE, data[3] & 4);
129
 
130
                        a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
131
                        a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
132
                        a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
133
                        a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
134
 
135
                        a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
136
 
137
                        return;
138
 
139
                case A3D_MODE_PXL:
140
 
141
                        input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
142
                        input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
143
 
144
                        input_report_key(dev, BTN_RIGHT,  data[2] & 1);
145
                        input_report_key(dev, BTN_LEFT,   data[3] & 2);
146
                        input_report_key(dev, BTN_MIDDLE, data[3] & 4);
147
                        input_report_key(dev, BTN_SIDE,   data[7] & 2);
148
                        input_report_key(dev, BTN_EXTRA,  data[7] & 4);
149
 
150
                        input_report_abs(dev, ABS_X,        ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
151
                        input_report_abs(dev, ABS_Y,        ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
152
                        input_report_abs(dev, ABS_RUDDER,   ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
153
                        input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
154
 
155
                        input_report_abs(dev, ABS_HAT0X, ( data[5]       & 1) - ((data[5] >> 2) & 1));
156
                        input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
157
                        input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3]       & 1));
158
                        input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4]       & 1));
159
 
160
                        input_report_key(dev, BTN_TRIGGER, data[8] & 1);
161
                        input_report_key(dev, BTN_THUMB,   data[8] & 2);
162
                        input_report_key(dev, BTN_TOP,     data[8] & 4);
163
                        input_report_key(dev, BTN_PINKIE,  data[7] & 1);
164
 
165
                        return;
166
        }
167
}
168
 
169
 
170
/*
171
 * a3d_timer() reads and analyzes A3D joystick data.
172
 */
173
 
174
static void a3d_timer(unsigned long private)
175
{
176
        struct a3d *a3d = (void *) private;
177
        unsigned char data[A3D_MAX_LENGTH];
178
        a3d->reads++;
179
        if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
180
                || data[0] != a3d->mode || a3d_csum(data, a3d->length))
181
                a3d->bads++; else a3d_read(a3d, data);
182
        mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
183
}
184
 
185
/*
186
 * a3d_adc_cooked_read() copies the acis and button data to the
187
 * callers arrays. It could do the read itself, but the caller could
188
 * call this more than 50 times a second, which would use too much CPU.
189
 */
190
 
191
int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
192
{
193
        struct a3d *a3d = gameport->driver;
194
        int i;
195
        for (i = 0; i < 4; i++)
196
                axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
197
        *buttons = a3d->buttons;
198
        return 0;
199
}
200
 
201
/*
202
 * a3d_adc_open() is the gameport open routine. It refuses to serve
203
 * any but cooked data.
204
 */
205
 
206
int a3d_adc_open(struct gameport *gameport, int mode)
207
{
208
        struct a3d *a3d = gameport->driver;
209
        if (mode != GAMEPORT_MODE_COOKED)
210
                return -1;
211
        if (!a3d->used++)
212
                mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
213
        return 0;
214
}
215
 
216
/*
217
 * a3d_adc_close() is a callback from the input close routine.
218
 */
219
 
220
static void a3d_adc_close(struct gameport *gameport)
221
{
222
        struct a3d *a3d = gameport->driver;
223
        if (!--a3d->used)
224
                del_timer(&a3d->timer);
225
}
226
 
227
/*
228
 * a3d_open() is a callback from the input open routine.
229
 */
230
 
231
static int a3d_open(struct input_dev *dev)
232
{
233
        struct a3d *a3d = dev->private;
234
        if (!a3d->used++)
235
                mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
236
        return 0;
237
}
238
 
239
/*
240
 * a3d_close() is a callback from the input close routine.
241
 */
242
 
243
static void a3d_close(struct input_dev *dev)
244
{
245
        struct a3d *a3d = dev->private;
246
        if (!--a3d->used)
247
                del_timer(&a3d->timer);
248
}
249
 
250
/*
251
 * a3d_connect() probes for A3D joysticks.
252
 */
253
 
254
static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
255
{
256
        struct a3d *a3d;
257
        unsigned char data[A3D_MAX_LENGTH];
258
        int i;
259
 
260
        if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
261
                return;
262
        memset(a3d, 0, sizeof(struct a3d));
263
 
264
        gameport->private = a3d;
265
 
266
        a3d->gameport = gameport;
267
        init_timer(&a3d->timer);
268
        a3d->timer.data = (long) a3d;
269
        a3d->timer.function = a3d_timer;
270
 
271
        if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
272
                goto fail1;
273
 
274
        i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
275
 
276
        if (!i || a3d_csum(data, i))
277
                goto fail2;
278
 
279
        a3d->mode = data[0];
280
 
281
        if (!a3d->mode || a3d->mode > 5) {
282
                printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
283
                        "(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
284
                goto fail2;
285
        }
286
 
287
 
288
        if (a3d->mode == A3D_MODE_PXL) {
289
 
290
                int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
291
 
292
                a3d->length = 33;
293
 
294
                a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
295
                a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
296
                a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
297
                                   | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
298
 
299
                a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
300
                                                 | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
301
 
302
                a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
303
 
304
                a3d_read(a3d, data);
305
 
306
                for (i = 0; i < 4; i++) {
307
                        if (i < 2) {
308
                                a3d->dev.absmin[axes[i]] = 48;
309
                                a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
310
                                a3d->dev.absflat[axes[i]] = 8;
311
                        } else {
312
                                a3d->dev.absmin[axes[i]] = 2;
313
                                a3d->dev.absmax[axes[i]] = 253;
314
                        }
315
                        a3d->dev.absmin[ABS_HAT0X + i] = -1;
316
                        a3d->dev.absmax[ABS_HAT0X + i] = 1;
317
                }
318
 
319
        } else {
320
                a3d->length = 29;
321
 
322
                a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
323
                a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
324
                a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
325
 
326
                a3d->adc.driver = a3d;
327
                a3d->adc.open = a3d_adc_open;
328
                a3d->adc.close = a3d_adc_close;
329
                a3d->adc.cooked_read = a3d_adc_cooked_read;
330
                a3d->adc.fuzz = 1;
331
 
332
                a3d_read(a3d, data);
333
 
334
                gameport_register_port(&a3d->adc);
335
                printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
336
                        a3d->adc.number, a3d_names[a3d->mode], gameport->number);
337
        }
338
 
339
        a3d->dev.private = a3d;
340
        a3d->dev.open = a3d_open;
341
        a3d->dev.close = a3d_close;
342
 
343
        a3d->dev.name = a3d_names[a3d->mode];
344
        a3d->dev.idbus = BUS_GAMEPORT;
345
        a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
346
        a3d->dev.idproduct = a3d->mode;
347
        a3d->dev.idversion = 0x0100;
348
 
349
        input_register_device(&a3d->dev);
350
        printk(KERN_INFO "input%d: %s on gameport%d.0\n",
351
                a3d->dev.number, a3d_names[a3d->mode], gameport->number);
352
 
353
        return;
354
fail2:  gameport_close(gameport);
355
fail1:  kfree(a3d);
356
}
357
 
358
static void a3d_disconnect(struct gameport *gameport)
359
{
360
 
361
        struct a3d *a3d = gameport->private;
362
        input_unregister_device(&a3d->dev);
363
        if (a3d->mode < A3D_MODE_PXL)
364
                gameport_unregister_port(&a3d->adc);
365
        gameport_close(gameport);
366
        kfree(a3d);
367
}
368
 
369
static struct gameport_dev a3d_dev = {
370
        connect:        a3d_connect,
371
        disconnect:     a3d_disconnect,
372
};
373
 
374
int __init a3d_init(void)
375
{
376
        gameport_register_device(&a3d_dev);
377
        return 0;
378
}
379
 
380
void __exit a3d_exit(void)
381
{
382
        gameport_unregister_device(&a3d_dev);
383
}
384
 
385
module_init(a3d_init);
386
module_exit(a3d_exit);
387
 
388
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.