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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * $Id: spaceorb.c,v 1.1.1.1 2004-04-15 02:03:30 phoenix Exp $
3
 *
4
 *  Copyright (c) 1999-2000 Vojtech Pavlik
5
 *
6
 *  Based on the work of:
7
 *      David Thompson
8
 *
9
 *  Sponsored by SuSE
10
 */
11
 
12
/*
13
 * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
14
 */
15
 
16
/*
17
 * This program is free software; you can redistribute it and/or modify
18
 * it under the terms of the GNU General Public License as published by
19
 * the Free Software Foundation; either version 2 of the License, or
20
 * (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program; if not, write to the Free Software
29
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30
 *
31
 *  Should you need to contact me, the author, you can do so either by
32
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
33
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
34
 */
35
 
36
#include <linux/kernel.h>
37
#include <linux/slab.h>
38
#include <linux/module.h>
39
#include <linux/init.h>
40
#include <linux/input.h>
41
#include <linux/serio.h>
42
 
43
/*
44
 * Constants.
45
 */
46
 
47
#define SPACEORB_MAX_LENGTH     64
48
 
49
static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
50
static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
51
static char *spaceorb_name = "SpaceTec SpaceOrb 360";
52
 
53
/*
54
 * Per-Orb data.
55
 */
56
 
57
struct spaceorb {
58
        struct input_dev dev;
59
        struct serio *serio;
60
        int idx;
61
        unsigned char data[SPACEORB_MAX_LENGTH];
62
};
63
 
64
static unsigned char spaceorb_xor[] = "SpaceWare";
65
 
66
static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
67
                "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
68
 
69
/*
70
 * spaceorb_process_packet() decodes packets the driver receives from the
71
 * SpaceOrb.
72
 */
73
 
74
static void spaceorb_process_packet(struct spaceorb *spaceorb)
75
{
76
        struct input_dev *dev = &spaceorb->dev;
77
        unsigned char *data = spaceorb->data;
78
        unsigned char c = 0;
79
        int axes[6];
80
        int i;
81
 
82
        if (spaceorb->idx < 2) return;
83
        for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
84
        if (c) return;
85
 
86
        switch (data[0]) {
87
 
88
                case 'R':                               /* Reset packet */
89
                        spaceorb->data[spaceorb->idx - 1] = 0;
90
                        for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
91
                        printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
92
                                 spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
93
                        break;
94
 
95
                case 'D':                               /* Ball + button data */
96
                        if (spaceorb->idx != 12) return;
97
                        for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i];
98
                        axes[0] = ( data[2]       << 3) | (data[ 3] >> 4);
99
                        axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
100
                        axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
101
                        axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
102
                        axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
103
                        axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
104
                        for (i = 0; i < 6; i++)
105
                                input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
106
                        for (i = 0; i < 8; i++)
107
                                input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
108
                        break;
109
 
110
                case 'K':                               /* Button data */
111
                        if (spaceorb->idx != 5) return;
112
                        for (i = 0; i < 7; i++)
113
                                input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
114
 
115
                        break;
116
 
117
                case 'E':                               /* Error packet */
118
                        if (spaceorb->idx != 4) return;
119
                        printk(KERN_ERR "joy-spaceorb: Device error. [ ");
120
                        for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
121
                        printk("]\n");
122
                        break;
123
        }
124
}
125
 
126
static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
127
{
128
        struct spaceorb* spaceorb = serio->private;
129
 
130
        if (~data & 0x80) {
131
                if (spaceorb->idx) spaceorb_process_packet(spaceorb);
132
                spaceorb->idx = 0;
133
        }
134
        if (spaceorb->idx < SPACEORB_MAX_LENGTH)
135
                spaceorb->data[spaceorb->idx++] = data & 0x7f;
136
}
137
 
138
/*
139
 * spaceorb_disconnect() is the opposite of spaceorb_connect()
140
 */
141
 
142
static void spaceorb_disconnect(struct serio *serio)
143
{
144
        struct spaceorb* spaceorb = serio->private;
145
        input_unregister_device(&spaceorb->dev);
146
        serio_close(serio);
147
        kfree(spaceorb);
148
}
149
 
150
/*
151
 * spaceorb_connect() is the routine that is called when someone adds a
152
 * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
153
 * it as an input device.
154
 */
155
 
156
static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
157
{
158
        struct spaceorb *spaceorb;
159
        int i, t;
160
 
161
        if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
162
                return;
163
 
164
        if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
165
                return;
166
        memset(spaceorb, 0, sizeof(struct spaceorb));
167
 
168
        spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
169
 
170
        for (i = 0; i < 7; i++)
171
                set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
172
 
173
        for (i = 0; i < 6; i++) {
174
                t = spaceorb_axes[i];
175
                set_bit(t, spaceorb->dev.absbit);
176
                spaceorb->dev.absmin[t] = -508;
177
                spaceorb->dev.absmax[t] =  508;
178
        }
179
 
180
        spaceorb->serio = serio;
181
        spaceorb->dev.private = spaceorb;
182
 
183
        spaceorb->dev.name = spaceorb_name;
184
        spaceorb->dev.idbus = BUS_RS232;
185
        spaceorb->dev.idvendor = SERIO_SPACEORB;
186
        spaceorb->dev.idproduct = 0x0001;
187
        spaceorb->dev.idversion = 0x0100;
188
 
189
        serio->private = spaceorb;
190
 
191
        if (serio_open(serio, dev)) {
192
                kfree(spaceorb);
193
                return;
194
        }
195
 
196
        input_register_device(&spaceorb->dev);
197
}
198
 
199
/*
200
 * The serio device structure.
201
 */
202
 
203
static struct serio_dev spaceorb_dev = {
204
        interrupt:      spaceorb_interrupt,
205
        connect:        spaceorb_connect,
206
        disconnect:     spaceorb_disconnect,
207
};
208
 
209
/*
210
 * The functions for inserting/removing us as a module.
211
 */
212
 
213
int __init spaceorb_init(void)
214
{
215
        serio_register_device(&spaceorb_dev);
216
        return 0;
217
}
218
 
219
void __exit spaceorb_exit(void)
220
{
221
        serio_unregister_device(&spaceorb_dev);
222
}
223
 
224
module_init(spaceorb_init);
225
module_exit(spaceorb_exit);
226
 
227
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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