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