gf2k.c (8791B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 1998-2001 Vojtech Pavlik 4 */ 5 6/* 7 * Genius Flight 2000 joystick driver for Linux 8 */ 9 10/* 11 */ 12 13#include <linux/delay.h> 14#include <linux/kernel.h> 15#include <linux/slab.h> 16#include <linux/module.h> 17#include <linux/input.h> 18#include <linux/gameport.h> 19#include <linux/jiffies.h> 20 21#define DRIVER_DESC "Genius Flight 2000 joystick driver" 22 23MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 24MODULE_DESCRIPTION(DRIVER_DESC); 25MODULE_LICENSE("GPL"); 26 27#define GF2K_START 400 /* The time we wait for the first bit [400 us] */ 28#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ 29#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ 30#define GF2K_LENGTH 80 /* Max number of triplets in a packet */ 31 32/* 33 * Genius joystick ids ... 34 */ 35 36#define GF2K_ID_G09 1 37#define GF2K_ID_F30D 2 38#define GF2K_ID_F30 3 39#define GF2K_ID_F31D 4 40#define GF2K_ID_F305 5 41#define GF2K_ID_F23P 6 42#define GF2K_ID_F31 7 43#define GF2K_ID_MAX 7 44 45static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 }; 46static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; 47 48static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D", 49 "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"}; 50static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 }; 51static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 }; 52static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 }; 53static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 }; 54static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 }; 55 56static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE }; 57static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }; 58static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT }; 59 60 61static short gf2k_seq_reset[] = { 240, 340, 0 }; 62static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; 63 64struct gf2k { 65 struct gameport *gameport; 66 struct input_dev *dev; 67 int reads; 68 int bads; 69 unsigned char id; 70 unsigned char length; 71 char phys[32]; 72}; 73 74/* 75 * gf2k_read_packet() reads a Genius Flight2000 packet. 76 */ 77 78static int gf2k_read_packet(struct gameport *gameport, int length, char *data) 79{ 80 unsigned char u, v; 81 int i; 82 unsigned int t, p; 83 unsigned long flags; 84 85 t = gameport_time(gameport, GF2K_START); 86 p = gameport_time(gameport, GF2K_STROBE); 87 88 i = 0; 89 90 local_irq_save(flags); 91 92 gameport_trigger(gameport); 93 v = gameport_read(gameport); 94 95 while (t > 0 && i < length) { 96 t--; u = v; 97 v = gameport_read(gameport); 98 if (v & ~u & 0x10) { 99 data[i++] = v >> 5; 100 t = p; 101 } 102 } 103 104 local_irq_restore(flags); 105 106 return i; 107} 108 109/* 110 * gf2k_trigger_seq() initializes a Genius Flight2000 joystick 111 * into digital mode. 112 */ 113 114static void gf2k_trigger_seq(struct gameport *gameport, short *seq) 115{ 116 117 unsigned long flags; 118 int i, t; 119 120 local_irq_save(flags); 121 122 i = 0; 123 do { 124 gameport_trigger(gameport); 125 t = gameport_time(gameport, GF2K_TIMEOUT * 1000); 126 while ((gameport_read(gameport) & 1) && t) t--; 127 udelay(seq[i]); 128 } while (seq[++i]); 129 130 gameport_trigger(gameport); 131 132 local_irq_restore(flags); 133} 134 135/* 136 * js_sw_get_bits() composes bits from the triplet buffer into a __u64. 137 * Parameter 'pos' is bit number inside packet where to start at, 'num' is number 138 * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits 139 * is number of bits per triplet. 140 */ 141 142#define GB(p,n,s) gf2k_get_bits(data, p, n, s) 143 144static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) 145{ 146 __u64 data = 0; 147 int i; 148 149 for (i = 0; i < num / 3 + 2; i++) 150 data |= buf[pos / 3 + i] << (i * 3); 151 data >>= pos % 3; 152 data &= (1 << num) - 1; 153 data <<= shift; 154 155 return data; 156} 157 158static void gf2k_read(struct gf2k *gf2k, unsigned char *data) 159{ 160 struct input_dev *dev = gf2k->dev; 161 int i, t; 162 163 for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) 164 input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9)); 165 166 for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++) 167 input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9)); 168 169 t = GB(40,4,0); 170 171 for (i = 0; i < gf2k_hats[gf2k->id]; i++) 172 input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); 173 174 t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); 175 176 for (i = 0; i < gf2k_joys[gf2k->id]; i++) 177 input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1); 178 179 for (i = 0; i < gf2k_pads[gf2k->id]; i++) 180 input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); 181 182 input_sync(dev); 183} 184 185/* 186 * gf2k_poll() reads and analyzes Genius joystick data. 187 */ 188 189static void gf2k_poll(struct gameport *gameport) 190{ 191 struct gf2k *gf2k = gameport_get_drvdata(gameport); 192 unsigned char data[GF2K_LENGTH]; 193 194 gf2k->reads++; 195 196 if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) 197 gf2k->bads++; 198 else 199 gf2k_read(gf2k, data); 200} 201 202static int gf2k_open(struct input_dev *dev) 203{ 204 struct gf2k *gf2k = input_get_drvdata(dev); 205 206 gameport_start_polling(gf2k->gameport); 207 return 0; 208} 209 210static void gf2k_close(struct input_dev *dev) 211{ 212 struct gf2k *gf2k = input_get_drvdata(dev); 213 214 gameport_stop_polling(gf2k->gameport); 215} 216 217/* 218 * gf2k_connect() probes for Genius id joysticks. 219 */ 220 221static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) 222{ 223 struct gf2k *gf2k; 224 struct input_dev *input_dev; 225 unsigned char data[GF2K_LENGTH]; 226 int i, err; 227 228 gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL); 229 input_dev = input_allocate_device(); 230 if (!gf2k || !input_dev) { 231 err = -ENOMEM; 232 goto fail1; 233 } 234 235 gf2k->gameport = gameport; 236 gf2k->dev = input_dev; 237 238 gameport_set_drvdata(gameport, gf2k); 239 240 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 241 if (err) 242 goto fail1; 243 244 gf2k_trigger_seq(gameport, gf2k_seq_reset); 245 246 msleep(GF2K_TIMEOUT); 247 248 gf2k_trigger_seq(gameport, gf2k_seq_digital); 249 250 msleep(GF2K_TIMEOUT); 251 252 if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) { 253 err = -ENODEV; 254 goto fail2; 255 } 256 257 if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) { 258 err = -ENODEV; 259 goto fail2; 260 } 261 262#ifdef RESET_WORKS 263 if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) && 264 (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) { 265 err = -ENODEV; 266 goto fail2; 267 } 268#else 269 gf2k->id = 6; 270#endif 271 272 if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { 273 printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n", 274 gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); 275 err = -ENODEV; 276 goto fail2; 277 } 278 279 gameport_set_poll_handler(gameport, gf2k_poll); 280 gameport_set_poll_interval(gameport, 20); 281 282 snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys); 283 284 gf2k->length = gf2k_lens[gf2k->id]; 285 286 input_dev->name = gf2k_names[gf2k->id]; 287 input_dev->phys = gf2k->phys; 288 input_dev->id.bustype = BUS_GAMEPORT; 289 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; 290 input_dev->id.product = gf2k->id; 291 input_dev->id.version = 0x0100; 292 input_dev->dev.parent = &gameport->dev; 293 294 input_set_drvdata(input_dev, gf2k); 295 296 input_dev->open = gf2k_open; 297 input_dev->close = gf2k_close; 298 299 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 300 301 for (i = 0; i < gf2k_axes[gf2k->id]; i++) 302 set_bit(gf2k_abs[i], input_dev->absbit); 303 304 for (i = 0; i < gf2k_hats[gf2k->id]; i++) 305 input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); 306 307 for (i = 0; i < gf2k_joys[gf2k->id]; i++) 308 set_bit(gf2k_btn_joy[i], input_dev->keybit); 309 310 for (i = 0; i < gf2k_pads[gf2k->id]; i++) 311 set_bit(gf2k_btn_pad[i], input_dev->keybit); 312 313 gf2k_read_packet(gameport, gf2k->length, data); 314 gf2k_read(gf2k, data); 315 316 for (i = 0; i < gf2k_axes[gf2k->id]; i++) { 317 int max = i < 2 ? 318 input_abs_get_val(input_dev, gf2k_abs[i]) * 2 : 319 input_abs_get_val(input_dev, gf2k_abs[0]) + 320 input_abs_get_val(input_dev, gf2k_abs[1]); 321 int flat = i < 2 ? 24 : 0; 322 323 input_set_abs_params(input_dev, gf2k_abs[i], 324 32, max - 32, 8, flat); 325 } 326 327 err = input_register_device(gf2k->dev); 328 if (err) 329 goto fail2; 330 331 return 0; 332 333 fail2: gameport_close(gameport); 334 fail1: gameport_set_drvdata(gameport, NULL); 335 input_free_device(input_dev); 336 kfree(gf2k); 337 return err; 338} 339 340static void gf2k_disconnect(struct gameport *gameport) 341{ 342 struct gf2k *gf2k = gameport_get_drvdata(gameport); 343 344 input_unregister_device(gf2k->dev); 345 gameport_close(gameport); 346 gameport_set_drvdata(gameport, NULL); 347 kfree(gf2k); 348} 349 350static struct gameport_driver gf2k_drv = { 351 .driver = { 352 .name = "gf2k", 353 }, 354 .description = DRIVER_DESC, 355 .connect = gf2k_connect, 356 .disconnect = gf2k_disconnect, 357}; 358 359module_gameport_driver(gf2k_drv);