1/* 2 * $Id: spaceball.c,v 1.1.1.1 2008/10/15 03:26:32 james26_jang 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 49static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; 50static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; 51 52/* 53 * Per-Ball data. 54 */ 55 56struct 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 69static 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 115static 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 153static 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 167static 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 214static 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 224int __init spaceball_init(void) 225{ 226 serio_register_device(&spaceball_dev); 227 return 0; 228} 229 230void __exit spaceball_exit(void) 231{ 232 serio_unregister_device(&spaceball_dev); 233} 234 235module_init(spaceball_init); 236module_exit(spaceball_exit); 237 238MODULE_LICENSE("GPL"); 239