File: /usr/src/linux/drivers/char/joystick/spaceball.c
1 /*
2 * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
3 *
4 * Copyright (c) 1999-2000 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * David Thompson
8 * Joseph Krahn
9 *
10 * Sponsored by SuSE
11 */
12
13 /*
14 * SpaceTec SpaceBall 4000 FLX driver for Linux
15 */
16
17 /*
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 *
32 * Should you need to contact me, the author, you can do so either by
33 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
34 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
35 */
36
37 #include <linux/kernel.h>
38 #include <linux/slab.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/input.h>
42 #include <linux/serio.h>
43
44 /*
45 * Constants.
46 */
47
48 #define JS_SBALL_MAX_LENGTH 128
49 static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
50 static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX";
51
52 /*
53 * Per-Ball data.
54 */
55
56 struct spaceball {
57 struct input_dev dev;
58 struct serio *serio;
59 int idx;
60 int escape;
61 unsigned char data[JS_SBALL_MAX_LENGTH];
62 };
63
64 /*
65 * spaceball_process_packet() decodes packets the driver receives from the
66 * SpaceBall.
67 */
68
69 static void spaceball_process_packet(struct spaceball* spaceball)
70 {
71 struct input_dev *dev = &spaceball->dev;
72 unsigned char *data = spaceball->data;
73 int i;
74
75 if (spaceball->idx < 2) return;
76
77 printk("%c %d\n", spaceball->data[0], spaceball->idx);
78
79 switch (spaceball->data[0]) {
80
81 case '@': /* Reset packet */
82 spaceball->data[spaceball->idx - 1] = 0;
83 for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
84 printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
85 spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
86 break;
87
88 case 'D': /* Ball data */
89 if (spaceball->idx != 15) return;
90 for (i = 0; i < 6; i++) {
91 input_report_abs(dev, spaceball_axes[i],
92 (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
93 }
94 break;
95
96 case '.': /* Button data, part2 */
97 if (spaceball->idx != 3) return;
98 input_report_key(dev, BTN_0, data[2] & 1);
99 input_report_key(dev, BTN_1, data[2] & 2);
100 break;
101
102 case '?': /* Error packet */
103 spaceball->data[spaceball->idx - 1] = 0;
104 printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
105 break;
106 }
107 }
108
109 /*
110 * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
111 * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
112 * can occur in the axis values.
113 */
114
115 static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
116 {
117 struct spaceball *spaceball = serio->private;
118
119 switch (data) {
120 case 0xd:
121 spaceball_process_packet(spaceball);
122 spaceball->idx = 0;
123 spaceball->escape = 0;
124 return;
125 case '^':
126 if (!spaceball->escape) {
127 spaceball->escape = 1;
128 return;
129 }
130 spaceball->escape = 0;
131 case 'M':
132 case 'Q':
133 case 'S':
134 if (spaceball->escape) {
135 spaceball->escape = 0;
136 data &= 0x1f;
137 }
138 default:
139 if (spaceball->escape) {
140 spaceball->escape = 0;
141 printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
142 }
143 if (spaceball->idx < JS_SBALL_MAX_LENGTH)
144 spaceball->data[spaceball->idx++] = data;
145 return;
146 }
147 }
148
149 /*
150 * spaceball_disconnect() is the opposite of spaceball_connect()
151 */
152
153 static void spaceball_disconnect(struct serio *serio)
154 {
155 struct spaceball* spaceball = serio->private;
156 input_unregister_device(&spaceball->dev);
157 serio_close(serio);
158 kfree(spaceball);
159 }
160
161 /*
162 * spaceball_connect() is the routine that is called when someone adds a
163 * new serio device. It looks for the Magellan, and if found, registers
164 * it as an input device.
165 */
166
167 static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
168 {
169 struct spaceball *spaceball;
170 int i, t;
171
172 if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
173 return;
174
175 if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
176 return;
177 memset(spaceball, 0, sizeof(struct spaceball));
178
179 spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
180 spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
181
182 for (i = 0; i < 6; i++) {
183 t = spaceball_axes[i];
184 set_bit(t, spaceball->dev.absbit);
185 spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
186 spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600;
187 spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
188 spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
189 }
190
191 spaceball->serio = serio;
192 spaceball->dev.private = spaceball;
193
194 spaceball->dev.name = spaceball_name;
195 spaceball->dev.idbus = BUS_RS232;
196 spaceball->dev.idvendor = SERIO_SPACEBALL;
197 spaceball->dev.idproduct = 0x0001;
198 spaceball->dev.idversion = 0x0100;
199
200 serio->private = spaceball;
201
202 if (serio_open(serio, dev)) {
203 kfree(spaceball);
204 return;
205 }
206
207 input_register_device(&spaceball->dev);
208 }
209
210 /*
211 * The serio device structure.
212 */
213
214 static struct serio_dev spaceball_dev = {
215 interrupt: spaceball_interrupt,
216 connect: spaceball_connect,
217 disconnect: spaceball_disconnect,
218 };
219
220 /*
221 * The functions for inserting/removing us as a module.
222 */
223
224 int __init spaceball_init(void)
225 {
226 serio_register_device(&spaceball_dev);
227 return 0;
228 }
229
230 void __exit spaceball_exit(void)
231 {
232 serio_unregister_device(&spaceball_dev);
233 }
234
235 module_init(spaceball_init);
236 module_exit(spaceball_exit);
237
238 MODULE_LICENSE("GPL");
239