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