spaceball.c (7487B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 1999-2001 Vojtech Pavlik 4 * 5 * Based on the work of: 6 * David Thompson 7 * Joseph Krahn 8 */ 9 10/* 11 * SpaceTec SpaceBall 2003/3003/4000 FLX driver for Linux 12 */ 13 14/* 15 */ 16 17#include <linux/kernel.h> 18#include <linux/slab.h> 19#include <linux/module.h> 20#include <linux/input.h> 21#include <linux/serio.h> 22#include <asm/unaligned.h> 23 24#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" 25 26MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 27MODULE_DESCRIPTION(DRIVER_DESC); 28MODULE_LICENSE("GPL"); 29 30/* 31 * Constants. 32 */ 33 34#define SPACEBALL_MAX_LENGTH 128 35#define SPACEBALL_MAX_ID 9 36 37#define SPACEBALL_1003 1 38#define SPACEBALL_2003B 3 39#define SPACEBALL_2003C 4 40#define SPACEBALL_3003C 7 41#define SPACEBALL_4000FLX 8 42#define SPACEBALL_4000FLX_L 9 43 44static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; 45static char *spaceball_names[] = { 46 "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", 47 "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", 48 "SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" }; 49 50/* 51 * Per-Ball data. 52 */ 53 54struct spaceball { 55 struct input_dev *dev; 56 int idx; 57 int escape; 58 unsigned char data[SPACEBALL_MAX_LENGTH]; 59 char phys[32]; 60}; 61 62/* 63 * spaceball_process_packet() decodes packets the driver receives from the 64 * SpaceBall. 65 */ 66 67static void spaceball_process_packet(struct spaceball* spaceball) 68{ 69 struct input_dev *dev = spaceball->dev; 70 unsigned char *data = spaceball->data; 71 int i; 72 73 if (spaceball->idx < 2) return; 74 75 switch (spaceball->data[0]) { 76 77 case 'D': /* Ball data */ 78 if (spaceball->idx != 15) return; 79 /* 80 * Skip first three bytes; read six axes worth of data. 81 * Axis values are signed 16-bit big-endian. 82 */ 83 data += 3; 84 for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) { 85 input_report_abs(dev, spaceball_axes[i], 86 (__s16)get_unaligned_be16(&data[i * 2])); 87 } 88 break; 89 90 case 'K': /* Button data */ 91 if (spaceball->idx != 3) return; 92 input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20)); 93 input_report_key(dev, BTN_2, data[2] & 0x02); 94 input_report_key(dev, BTN_3, data[2] & 0x04); 95 input_report_key(dev, BTN_4, data[2] & 0x08); 96 input_report_key(dev, BTN_5, data[1] & 0x01); 97 input_report_key(dev, BTN_6, data[1] & 0x02); 98 input_report_key(dev, BTN_7, data[1] & 0x04); 99 input_report_key(dev, BTN_8, data[1] & 0x10); 100 break; 101 102 case '.': /* Advanced button data */ 103 if (spaceball->idx != 3) return; 104 input_report_key(dev, BTN_1, data[2] & 0x01); 105 input_report_key(dev, BTN_2, data[2] & 0x02); 106 input_report_key(dev, BTN_3, data[2] & 0x04); 107 input_report_key(dev, BTN_4, data[2] & 0x08); 108 input_report_key(dev, BTN_5, data[2] & 0x10); 109 input_report_key(dev, BTN_6, data[2] & 0x20); 110 input_report_key(dev, BTN_7, data[2] & 0x80); 111 input_report_key(dev, BTN_8, data[1] & 0x01); 112 input_report_key(dev, BTN_9, data[1] & 0x02); 113 input_report_key(dev, BTN_A, data[1] & 0x04); 114 input_report_key(dev, BTN_B, data[1] & 0x08); 115 input_report_key(dev, BTN_C, data[1] & 0x10); 116 input_report_key(dev, BTN_MODE, data[1] & 0x20); 117 break; 118 119 case 'E': /* Device error */ 120 spaceball->data[spaceball->idx - 1] = 0; 121 printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1); 122 break; 123 124 case '?': /* Bad command packet */ 125 spaceball->data[spaceball->idx - 1] = 0; 126 printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1); 127 break; 128 } 129 130 input_sync(dev); 131} 132 133/* 134 * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, 135 * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which 136 * can occur in the axis values. 137 */ 138 139static irqreturn_t spaceball_interrupt(struct serio *serio, 140 unsigned char data, unsigned int flags) 141{ 142 struct spaceball *spaceball = serio_get_drvdata(serio); 143 144 switch (data) { 145 case 0xd: 146 spaceball_process_packet(spaceball); 147 spaceball->idx = 0; 148 spaceball->escape = 0; 149 break; 150 case '^': 151 if (!spaceball->escape) { 152 spaceball->escape = 1; 153 break; 154 } 155 spaceball->escape = 0; 156 fallthrough; 157 case 'M': 158 case 'Q': 159 case 'S': 160 if (spaceball->escape) { 161 spaceball->escape = 0; 162 data &= 0x1f; 163 } 164 fallthrough; 165 default: 166 if (spaceball->escape) 167 spaceball->escape = 0; 168 if (spaceball->idx < SPACEBALL_MAX_LENGTH) 169 spaceball->data[spaceball->idx++] = data; 170 break; 171 } 172 return IRQ_HANDLED; 173} 174 175/* 176 * spaceball_disconnect() is the opposite of spaceball_connect() 177 */ 178 179static void spaceball_disconnect(struct serio *serio) 180{ 181 struct spaceball* spaceball = serio_get_drvdata(serio); 182 183 serio_close(serio); 184 serio_set_drvdata(serio, NULL); 185 input_unregister_device(spaceball->dev); 186 kfree(spaceball); 187} 188 189/* 190 * spaceball_connect() is the routine that is called when someone adds a 191 * new serio device that supports Spaceball protocol and registers it as 192 * an input device. 193 */ 194 195static int spaceball_connect(struct serio *serio, struct serio_driver *drv) 196{ 197 struct spaceball *spaceball; 198 struct input_dev *input_dev; 199 int err = -ENOMEM; 200 int i, id; 201 202 if ((id = serio->id.id) > SPACEBALL_MAX_ID) 203 return -ENODEV; 204 205 spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL); 206 input_dev = input_allocate_device(); 207 if (!spaceball || !input_dev) 208 goto fail1; 209 210 spaceball->dev = input_dev; 211 snprintf(spaceball->phys, sizeof(spaceball->phys), "%s/input0", serio->phys); 212 213 input_dev->name = spaceball_names[id]; 214 input_dev->phys = spaceball->phys; 215 input_dev->id.bustype = BUS_RS232; 216 input_dev->id.vendor = SERIO_SPACEBALL; 217 input_dev->id.product = id; 218 input_dev->id.version = 0x0100; 219 input_dev->dev.parent = &serio->dev; 220 221 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 222 223 switch (id) { 224 case SPACEBALL_4000FLX: 225 case SPACEBALL_4000FLX_L: 226 input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_9); 227 input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) | 228 BIT_MASK(BTN_B) | BIT_MASK(BTN_C) | 229 BIT_MASK(BTN_MODE); 230 fallthrough; 231 default: 232 input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) | 233 BIT_MASK(BTN_3) | BIT_MASK(BTN_4) | 234 BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | 235 BIT_MASK(BTN_7) | BIT_MASK(BTN_8); 236 fallthrough; 237 case SPACEBALL_3003C: 238 input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) | 239 BIT_MASK(BTN_8); 240 } 241 242 for (i = 0; i < 3; i++) { 243 input_set_abs_params(input_dev, ABS_X + i, -8000, 8000, 8, 40); 244 input_set_abs_params(input_dev, ABS_RX + i, -1600, 1600, 2, 8); 245 } 246 247 serio_set_drvdata(serio, spaceball); 248 249 err = serio_open(serio, drv); 250 if (err) 251 goto fail2; 252 253 err = input_register_device(spaceball->dev); 254 if (err) 255 goto fail3; 256 257 return 0; 258 259 fail3: serio_close(serio); 260 fail2: serio_set_drvdata(serio, NULL); 261 fail1: input_free_device(input_dev); 262 kfree(spaceball); 263 return err; 264} 265 266/* 267 * The serio driver structure. 268 */ 269 270static const struct serio_device_id spaceball_serio_ids[] = { 271 { 272 .type = SERIO_RS232, 273 .proto = SERIO_SPACEBALL, 274 .id = SERIO_ANY, 275 .extra = SERIO_ANY, 276 }, 277 { 0 } 278}; 279 280MODULE_DEVICE_TABLE(serio, spaceball_serio_ids); 281 282static struct serio_driver spaceball_drv = { 283 .driver = { 284 .name = "spaceball", 285 }, 286 .description = DRIVER_DESC, 287 .id_table = spaceball_serio_ids, 288 .interrupt = spaceball_interrupt, 289 .connect = spaceball_connect, 290 .disconnect = spaceball_disconnect, 291}; 292 293module_serio_driver(spaceball_drv);