2 * joy-spaceball.c Version 0.1
4 * Copyright (c) 1998 David Thompson
5 * Copyright (c) 1999 Vojtech Pavlik
6 * Copyright (c) 1999 Joseph Krahn
12 * This is a module for the Linux joystick driver, supporting
13 * the SpaceTec SpaceBall 4000 FLX.
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.
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.
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
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
37 #include <asm/system.h>
38 #include <linux/errno.h>
39 #include <linux/joystick.h>
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/tty.h>
43 #include <linux/init.h>
49 #define N_JOYSTICK_SBALL 12
50 #define JS_SBALL_MAX_LENGTH 128
56 static struct js_port
* js_sball_port
= NULL
;
62 struct js_sball_info
{
63 struct tty_struct
* tty
;
66 unsigned char data
[JS_SBALL_MAX_LENGTH
];
72 * js_sball_process_packet() decodes packets the driver receives from the
76 static void js_sball_process_packet(struct js_sball_info
* info
)
79 int **axes
= info
->port
->axes
;
80 int **buttons
= info
->port
->buttons
;
81 unsigned char *data
= info
->data
;
83 if (info
->idx
< 2) return;
85 switch (info
->data
[0]) {
87 case '@': /* Reset packet */
88 info
->data
[info
->idx
- 1] = 0;
89 for (i
= 1; i
< info
->idx
&& info
->data
[i
] == ' '; i
++);
91 printk(KERN_INFO
"js%d: SpaceBall 4000FLX [%s] on %s%d\n",
92 info
->js
, info
->data
+ i
, info
->tty
->driver
.name
,
93 MINOR(info
->tty
->device
) - info
->tty
->driver
.minor_start
);
95 memset(axes
[0], 0, sizeof(int) * 6); /* All axes, buttons should be zero */
99 case 'D': /* Ball data */
100 if (info
->idx
!= 16) return;
101 if (!info
->port
->devs
[0]) return;
102 axes
[0][0] = ((data
[3] << 8) | data
[4] );
103 axes
[0][1] = ((data
[5] << 8) | data
[6] );
104 axes
[0][2] = ((data
[7] << 8) | data
[8] );
105 axes
[0][3] = ((data
[9] << 8) | data
[10]);
106 axes
[0][4] = ((data
[11]<< 8) | data
[12]);
107 axes
[0][5] = ((data
[13]<< 8) | data
[14]);
108 for(i
= 0; i
< 6; i
++) if (axes
[0][i
] & 0x8000) axes
[0][i
] -= 0x10000;
111 case 'K': /* Button data, part1 */
112 /* We can ignore this packet for the SB 4000FLX. */
115 case '.': /* Button data, part2 */
116 if (info
->idx
!= 4) return;
117 if (!info
->port
->devs
[0]) return;
118 b
= (data
[1] & 0xbf) << 8 | (data
[2] & 0xbf);
119 buttons
[0][0] = ((b
& 0x1f80) >> 1 | (b
& 0x3f));
122 case '?': /* Error packet */
123 info
->data
[info
->idx
- 1] = 0;
124 printk(KERN_ERR
"joy-spaceball: Device error. [%s]\n",info
->data
+1);
127 case 'A': /* reply to A command (ID# report) */
128 case 'B': /* reply to B command (beep) */
129 case 'H': /* reply to H command (firmware report) */
130 case 'S': /* reply to S command (single beep) */
131 case 'Y': /* reply to Y command (scale flag) */
132 case '"': /* reply to "n command (report info, part n) */
135 case 'P': /* Pulse (update) speed */
136 if (info
->idx
!= 3) return; /* data[2],data[3] = hex digits for speed 00-FF */
140 printk("joy-spaceball: Unknown packet %d length %d:", data
[0], info
->idx
);
141 for (i
= 0; i
< info
->idx
; i
++) printk(" %02x", data
[i
]);
148 * js_sball_open() is a callback from the joystick device open routine.
151 static int js_sball_open(struct js_dev
*jd
)
153 struct js_sball_info
*info
= jd
->port
->info
;
159 * js_sball_close() is a callback from the joystick device release routine.
162 static int js_sball_close(struct js_dev
*jd
)
164 struct js_sball_info
*info
= jd
->port
->info
;
166 js_unregister_device(jd
->port
->devs
[0]);
167 js_sball_port
= js_unregister_port(jd
->port
);
173 * js_sball_init_corr() initializes the correction values for the SpaceBall.
176 static void __init
js_sball_init_corr(struct js_corr
**corr
)
180 for (j
= 0; j
< 3; j
++) {
181 corr
[0][j
].type
= JS_CORR_BROKEN
;
183 corr
[0][j
].coef
[0] = 0;
184 corr
[0][j
].coef
[1] = 0;
185 corr
[0][j
].coef
[2] = 50000;
186 corr
[0][j
].coef
[3] = 50000;
188 for (j
= 3; j
< 6; j
++) {
189 corr
[0][j
].type
= JS_CORR_BROKEN
;
191 corr
[0][j
].coef
[0] = 0;
192 corr
[0][j
].coef
[1] = 0;
193 corr
[0][j
].coef
[2] = 300000;
194 corr
[0][j
].coef
[3] = 300000;
199 * js_sball_ldisc_open() is the routine that is called upon setting our line
200 * discipline on a tty.
203 static int js_sball_ldisc_open(struct tty_struct
*tty
)
205 struct js_sball_info iniinfo
;
206 struct js_sball_info
*info
= &iniinfo
;
214 js_sball_port
= js_register_port(js_sball_port
, info
, 1, sizeof(struct js_sball_info
), NULL
);
216 info
= js_sball_port
->info
;
217 info
->port
= js_sball_port
;
218 tty
->disc_data
= info
;
220 info
->js
= js_register_device(js_sball_port
, 0, 6, 12, "SpaceBall 4000 FLX", THIS_MODULE
, js_sball_open
, js_sball_close
);
222 js_sball_init_corr(js_sball_port
->corr
);
228 * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open()
231 static void js_sball_ldisc_close(struct tty_struct
*tty
)
233 struct js_sball_info
* info
= (struct js_sball_info
*) tty
->disc_data
;
235 js_unregister_device(info
->port
->devs
[0]);
236 js_sball_port
= js_unregister_port(info
->port
);
242 * js_sball_ldisc_receive() is called by the low level driver when characters
243 * are ready for us. We then buffer them for further processing, or call the
244 * packet processing routine.
247 static void js_sball_ldisc_receive(struct tty_struct
*tty
, const unsigned char *cp
, char *fp
, int count
)
249 struct js_sball_info
* info
= (struct js_sball_info
*) tty
->disc_data
;
254 * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
255 * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can
256 * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
257 * on whether the axis value is increasing, decreasing, or same as before.
258 * (I don't see why this is useful).
260 * There may be a nicer whay to handle the escapes, but I wanted to be sure to
261 * allow for an escape at the end of the buffer.
263 for (i
= 0; i
< count
; i
++) {
264 if (esc_flag
) { /* If the last char was an escape, overwrite it with the escaped value */
270 info
->data
[info
->idx
]=0x0d;
272 case '^': /* escaped escape; leave as is */
275 printk("joy-spaceball: Unknown escape character: %02x\n", cp
[i
]);
282 if (info
->idx
< JS_SBALL_MAX_LENGTH
)
283 info
->data
[info
->idx
++] = cp
[i
];
287 js_sball_process_packet(info
);
290 if (cp
[i
] == '^') esc_flag
= 1;
297 * js_sball_ldisc_room() reports how much room we do have for receiving data.
298 * Although we in fact have infinite room, we need to specify some value
299 * here, so why not the size of our packet buffer. It's big anyway.
302 static int js_sball_ldisc_room(struct tty_struct
*tty
)
304 return JS_SBALL_MAX_LENGTH
;
308 * The line discipline structure.
311 static struct tty_ldisc js_sball_ldisc
= {
312 magic
: TTY_LDISC_MAGIC
,
314 open
: js_sball_ldisc_open
,
315 close
: js_sball_ldisc_close
,
316 receive_buf
: js_sball_ldisc_receive
,
317 receive_room
: js_sball_ldisc_room
,
321 * The functions for inserting/removing us as a module.
325 int init_module(void)
327 int __init
js_sball_init(void)
330 if (tty_register_ldisc(N_JOYSTICK_SBALL
, &js_sball_ldisc
)) {
331 printk(KERN_ERR
"joy-spaceball: Error registering line discipline.\n");
339 void cleanup_module(void)
341 tty_register_ldisc(N_JOYSTICK_SBALL
, NULL
);