Import 2.4.0-test2pre6
[davej-history.git] / drivers / char / joystick / joy-spaceorb.c
blob0fb4f4c7128a73a27ffc174b9a24e7a51965f7ec
1 /*
2 * joy-spaceorb.c Version 0.1
4 * Copyright (c) 1998 David Thompson
5 * Copyright (c) 1999 Vojtech Pavlik
7 * Sponsored by SuSE
8 */
11 * This is a module for the Linux joystick driver, supporting
12 * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * Should you need to contact me, the author, you can do so either by
31 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
32 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
35 #include <asm/io.h>
36 #include <asm/system.h>
37 #include <linux/errno.h>
38 #include <linux/joystick.h>
39 #include <linux/kernel.h>
40 #include <linux/module.h>
41 #include <linux/tty.h>
42 #include <linux/init.h>
45 * Constants.
48 #define N_JOYSTICK_ORB 15
49 #define JS_ORB_MAX_LENGTH 64
52 * List of SpaceOrbs.
55 static struct js_port* js_orb_port = NULL;
58 * Per-Orb data.
61 struct js_orb_info {
62 struct tty_struct* tty;
63 struct js_port* port;
64 int idx;
65 unsigned char data[JS_ORB_MAX_LENGTH];
66 int js;
67 char used;
70 static unsigned char js_orb_xor[] = "SpaceWare";
72 static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
73 "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
76 * js_orb_process_packet() decodes packets the driver receives from the
77 * SpaceOrb.
80 static void js_orb_process_packet(struct js_orb_info* info)
82 int i;
83 int **axes = info->port->axes;
84 int **buttons = info->port->buttons;
85 unsigned char *data = info->data;
86 unsigned char c = 0;
88 if (info->idx < 2) return;
89 for (i = 0; i < info->idx; i++) c ^= data[i];
90 if (c) return;
92 switch (info->data[0]) {
94 case 'R': /* Reset packet */
95 info->data[info->idx - 1] = 0;
96 for (i = 1; i < info->idx && info->data[i] == ' '; i++);
97 printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n",
98 info->js, info->data + i, info->tty->driver.name,
99 MINOR(info->tty->device) - info->tty->driver.minor_start);
100 break;
102 case 'D': /* Ball + button data */
103 if (info->idx != 12) return;
104 if (!info->port->devs[0]) return;
105 for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i];
106 axes[0][0] = ( data[2] << 3) | (data[ 3] >> 4);
107 axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
108 axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
109 axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
110 axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
111 axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
112 for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024;
113 buttons[0][0] = data[1];
114 break;
116 case 'K': /* Button data */
117 if (info->idx != 5) return;
118 if (!info->port->devs[0]) return;
119 buttons[0][0] = data[2];
120 break;
122 case 'E': /* Error packet */
123 if (info->idx != 4) return;
124 printk(KERN_ERR "joy-spaceorb: Device error. [ ");
125 for (i = 0; i < 7; i++)
126 if (data[1] & (1 << i))
127 printk("%s ", js_orb_errors[i]);
128 printk("]\n");
129 break;
131 case 'N': /* Null region */
132 if (info->idx != 3) return;
133 break;
135 case 'P': /* Pulse (update) speed */
136 if (info->idx != 4) return;
137 break;
139 default:
140 printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx);
141 for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
142 printk("\n");
143 return;
148 * js_orb_open() is a callback from the joystick device open routine.
151 static int js_orb_open(struct js_dev *jd)
153 struct js_orb_info *info = jd->port->info;
154 info->used++;
155 return 0;
159 * js_orb_close() is a callback from the joystick device release routine.
162 static int js_orb_close(struct js_dev *jd)
164 struct js_orb_info *info = jd->port->info;
165 if (!--info->used) {
166 js_unregister_device(jd->port->devs[0]);
167 js_orb_port = js_unregister_port(jd->port);
169 return 0;
173 * js_orb_init_corr() initializes the correction values for the SpaceOrb.
176 static void __init js_orb_init_corr(struct js_corr **corr)
178 int j;
180 for (j = 0; j < 6; j++) {
181 corr[0][j].type = JS_CORR_BROKEN;
182 corr[0][j].prec = 0;
183 corr[0][j].coef[0] = 0 ;
184 corr[0][j].coef[1] = 0 ;
185 corr[0][j].coef[2] = (1 << 29) / 511;
186 corr[0][j].coef[3] = (1 << 29) / 511;
191 * js_orb_ldisc_open() is the routine that is called upon setting our line
192 * discipline on a tty.
195 static int js_orb_ldisc_open(struct tty_struct *tty)
197 struct js_orb_info iniinfo;
198 struct js_orb_info *info = &iniinfo;
200 MOD_INC_USE_COUNT;
202 info->tty = tty;
203 info->idx = 0;
204 info->used = 1;
206 js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL);
208 info = js_orb_port->info;
209 info->port = js_orb_port;
210 tty->disc_data = info;
212 info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", THIS_MODULE, js_orb_open, js_orb_close);
214 js_orb_init_corr(js_orb_port->corr);
216 return 0;
220 * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open()
223 static void js_orb_ldisc_close(struct tty_struct *tty)
225 struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
226 if (!--info->used) {
227 js_unregister_device(info->port->devs[0]);
228 js_orb_port = js_unregister_port(info->port);
230 MOD_DEC_USE_COUNT;
234 * js_orb_ldisc_receive() is called by the low level driver when characters
235 * are ready for us. We then buffer them for further processing, or call the
236 * packet processing routine.
239 static void js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
241 struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
242 int i;
244 for (i = 0; i < count; i++) {
245 if (~cp[i] & 0x80) {
246 if (info->idx) js_orb_process_packet(info);
247 info->idx = 0;
249 if (info->idx < JS_ORB_MAX_LENGTH)
250 info->data[info->idx++] = cp[i] & 0x7f;
255 * js_orb_ldisc_room() reports how much room we do have for receiving data.
256 * Although we in fact have infinite room, we need to specify some value
257 * here, so why not the size of our packet buffer. It's big anyway.
260 static int js_orb_ldisc_room(struct tty_struct *tty)
262 return JS_ORB_MAX_LENGTH;
266 * The line discipline structure.
269 static struct tty_ldisc js_orb_ldisc = {
270 magic: TTY_LDISC_MAGIC,
271 name: "spaceorb",
272 open: js_orb_ldisc_open,
273 close: js_orb_ldisc_close,
274 receive_buf: js_orb_ldisc_receive,
275 receive_room: js_orb_ldisc_room,
279 * The functions for inserting/removing us as a module.
282 #ifdef MODULE
283 int init_module(void)
284 #else
285 int __init js_orb_init(void)
286 #endif
288 if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) {
289 printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n");
290 return -ENODEV;
293 return 0;
296 #ifdef MODULE
297 void cleanup_module(void)
299 tty_register_ldisc(N_JOYSTICK_ORB, NULL);
301 #endif