1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 1998-2005 Vojtech Pavlik
7 * Logitech ADI joystick family driver for Linux
10 #include <linux/delay.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/string.h>
14 #include <linux/slab.h>
15 #include <linux/input.h>
16 #include <linux/gameport.h>
17 #include <linux/jiffies.h>
19 #define DRIVER_DESC "Logitech ADI joystick family driver"
21 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
22 MODULE_DESCRIPTION(DRIVER_DESC
);
23 MODULE_LICENSE("GPL");
26 * Times, array sizes, flags, ids.
29 #define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
30 #define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
31 #define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
32 #define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
34 #define ADI_MAX_LENGTH 256
35 #define ADI_MIN_LENGTH 8
36 #define ADI_MIN_LEN_LENGTH 10
37 #define ADI_MIN_ID_LENGTH 66
38 #define ADI_MAX_NAME_LENGTH 64
39 #define ADI_MAX_CNAME_LENGTH 16
40 #define ADI_MAX_PHYS_LENGTH 64
42 #define ADI_FLAG_HAT 0x04
43 #define ADI_FLAG_10BIT 0x08
45 #define ADI_ID_TPD 0x01
46 #define ADI_ID_WGP 0x06
47 #define ADI_ID_WGPE 0x08
48 #define ADI_ID_MAX 0x0a
51 * Names, buttons, axes ...
54 static char *adi_names
[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
55 "WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
56 "WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
57 "WingMan GamePad USB", "Unknown Device %#x" };
59 static char adi_wmgpe_abs
[] = { ABS_X
, ABS_Y
, ABS_HAT0X
, ABS_HAT0Y
};
60 static char adi_wmi_abs
[] = { ABS_X
, ABS_Y
, ABS_THROTTLE
, ABS_HAT0X
, ABS_HAT0Y
, ABS_HAT1X
, ABS_HAT1Y
, ABS_HAT2X
, ABS_HAT2Y
};
61 static char adi_wmed3d_abs
[] = { ABS_X
, ABS_Y
, ABS_THROTTLE
, ABS_RZ
, ABS_HAT0X
, ABS_HAT0Y
};
62 static char adi_cm2_abs
[] = { ABS_X
, ABS_Y
, ABS_Z
, ABS_RX
, ABS_RY
, ABS_RZ
};
63 static char adi_wmf_abs
[] = { ABS_WHEEL
, ABS_GAS
, ABS_BRAKE
, ABS_HAT0X
, ABS_HAT0Y
, ABS_HAT1X
, ABS_HAT1Y
, ABS_HAT2X
, ABS_HAT2Y
};
65 static short adi_wmgpe_key
[] = { BTN_A
, BTN_B
, BTN_C
, BTN_X
, BTN_Y
, BTN_Z
, BTN_TL
, BTN_TR
, BTN_START
, BTN_MODE
, BTN_SELECT
};
66 static short adi_wmi_key
[] = { BTN_TRIGGER
, BTN_TOP
, BTN_THUMB
, BTN_TOP2
, BTN_BASE
, BTN_BASE2
, BTN_BASE3
, BTN_BASE4
, BTN_EXTRA
};
67 static short adi_wmed3d_key
[] = { BTN_TRIGGER
, BTN_THUMB
, BTN_THUMB2
, BTN_TOP
, BTN_TOP2
, BTN_BASE
, BTN_BASE2
};
68 static short adi_cm2_key
[] = { BTN_1
, BTN_2
, BTN_3
, BTN_4
, BTN_5
, BTN_6
, BTN_7
, BTN_8
};
70 static char* adi_abs
[] = { adi_wmi_abs
, adi_wmgpe_abs
, adi_wmf_abs
, adi_cm2_abs
, adi_wmi_abs
, adi_wmf_abs
,
71 adi_wmgpe_abs
, adi_wmed3d_abs
, adi_wmgpe_abs
, adi_wmgpe_abs
, adi_wmi_abs
};
73 static short* adi_key
[] = { adi_wmi_key
, adi_wmgpe_key
, adi_cm2_key
, adi_cm2_key
, adi_wmi_key
, adi_cm2_key
,
74 adi_wmgpe_key
, adi_wmed3d_key
, adi_wmgpe_key
, adi_wmgpe_key
, adi_wmi_key
};
77 * Hat to axis conversion arrays.
83 } adi_hat_to_axis
[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
86 * Per-port information.
90 struct input_dev
*dev
;
102 char name
[ADI_MAX_NAME_LENGTH
];
103 char cname
[ADI_MAX_CNAME_LENGTH
];
104 char phys
[ADI_MAX_PHYS_LENGTH
];
105 unsigned char data
[ADI_MAX_LENGTH
];
109 struct gameport
*gameport
;
116 * adi_read_packet() reads a Logitech ADI packet.
119 static void adi_read_packet(struct adi_port
*port
)
121 struct adi
*adi
= port
->adi
;
122 struct gameport
*gameport
= port
->gameport
;
123 unsigned char u
, v
, w
, x
;
127 for (i
= 0; i
< 2; i
++) {
129 t
[i
] = gameport_time(gameport
, ADI_MAX_START
);
133 local_irq_save(flags
);
135 gameport_trigger(gameport
);
136 v
= gameport_read(gameport
);
140 w
= u
^ (v
= x
= gameport_read(gameport
));
141 for (i
= 0; i
< 2; i
++, w
>>= 2, x
>>= 2) {
143 if ((w
& 0x30) && s
[i
]) {
144 if ((w
& 0x30) < 0x30 && adi
[i
].ret
< ADI_MAX_LENGTH
&& t
[i
] > 0) {
145 adi
[i
].data
[++adi
[i
].ret
] = w
;
146 t
[i
] = gameport_time(gameport
, ADI_MAX_STROBE
);
148 } else if (!(x
& 0x30)) s
[i
] = 1;
150 } while (t
[0] > 0 || t
[1] > 0);
152 local_irq_restore(flags
);
158 * adi_move_bits() detects a possible 2-stream mode, and moves
159 * the bits accordingly.
162 static void adi_move_bits(struct adi_port
*port
, int length
)
165 struct adi
*adi
= port
->adi
;
167 adi
[0].idx
= adi
[1].idx
= 0;
169 if (adi
[0].ret
<= 0 || adi
[1].ret
<= 0) return;
170 if (adi
[0].data
[0] & 0x20 || ~adi
[1].data
[0] & 0x20) return;
172 for (i
= 1; i
<= adi
[1].ret
; i
++)
173 adi
[0].data
[((length
- 1) >> 1) + i
+ 1] = adi
[1].data
[i
];
175 adi
[0].ret
+= adi
[1].ret
;
180 * adi_get_bits() gathers bits from the data packet.
183 static inline int adi_get_bits(struct adi
*adi
, int count
)
187 if ((adi
->idx
+= count
) > adi
->ret
) return 0;
188 for (i
= 0; i
< count
; i
++)
189 bits
|= ((adi
->data
[adi
->idx
- i
] >> 5) & 1) << i
;
194 * adi_decode() decodes Logitech joystick data into input events.
197 static int adi_decode(struct adi
*adi
)
199 struct input_dev
*dev
= adi
->dev
;
200 char *abs
= adi
->abs
;
201 short *key
= adi
->key
;
204 if (adi
->ret
< adi
->length
|| adi
->id
!= (adi_get_bits(adi
, 4) | (adi_get_bits(adi
, 4) << 4)))
207 for (i
= 0; i
< adi
->axes10
; i
++)
208 input_report_abs(dev
, *abs
++, adi_get_bits(adi
, 10));
210 for (i
= 0; i
< adi
->axes8
; i
++)
211 input_report_abs(dev
, *abs
++, adi_get_bits(adi
, 8));
213 for (i
= 0; i
< adi
->buttons
&& i
< 63; i
++) {
215 t
= adi_get_bits(adi
, 4);
216 input_report_abs(dev
, *abs
++, ((t
>> 2) & 1) - ( t
& 1));
217 input_report_abs(dev
, *abs
++, ((t
>> 1) & 1) - ((t
>> 3) & 1));
219 input_report_key(dev
, *key
++, adi_get_bits(adi
, 1));
222 for (i
= 0; i
< adi
->hats
; i
++) {
223 if ((t
= adi_get_bits(adi
, 4)) > 8) t
= 0;
224 input_report_abs(dev
, *abs
++, adi_hat_to_axis
[t
].x
);
225 input_report_abs(dev
, *abs
++, adi_hat_to_axis
[t
].y
);
228 for (i
= 63; i
< adi
->buttons
; i
++)
229 input_report_key(dev
, *key
++, adi_get_bits(adi
, 1));
237 * adi_read() reads the data packet and decodes it.
240 static int adi_read(struct adi_port
*port
)
245 adi_read_packet(port
);
246 adi_move_bits(port
, port
->adi
[0].length
);
248 for (i
= 0; i
< 2; i
++)
249 if (port
->adi
[i
].length
)
250 result
|= adi_decode(port
->adi
+ i
);
256 * adi_poll() repeatedly polls the Logitech joysticks.
259 static void adi_poll(struct gameport
*gameport
)
261 struct adi_port
*port
= gameport_get_drvdata(gameport
);
263 port
->bad
-= adi_read(port
);
268 * adi_open() is a callback from the input open routine.
271 static int adi_open(struct input_dev
*dev
)
273 struct adi_port
*port
= input_get_drvdata(dev
);
275 gameport_start_polling(port
->gameport
);
280 * adi_close() is a callback from the input close routine.
283 static void adi_close(struct input_dev
*dev
)
285 struct adi_port
*port
= input_get_drvdata(dev
);
287 gameport_stop_polling(port
->gameport
);
291 * adi_init_digital() sends a trigger & delay sequence
292 * to reset and initialize a Logitech joystick into digital mode.
295 static void adi_init_digital(struct gameport
*gameport
)
297 static const int seq
[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
300 for (i
= 0; seq
[i
]; i
++) {
301 gameport_trigger(gameport
);
306 udelay(-seq
[i
]*14); /* It looks like mdelay() is off by approx 1.4% */
311 static void adi_id_decode(struct adi
*adi
, struct adi_port
*port
)
315 if (adi
->ret
< ADI_MIN_ID_LENGTH
) /* Minimum ID packet length */
318 if (adi
->ret
< (t
= adi_get_bits(adi
, 10))) {
319 printk(KERN_WARNING
"adi: Short ID packet: reported: %d != read: %d\n", t
, adi
->ret
);
323 adi
->id
= adi_get_bits(adi
, 4) | (adi_get_bits(adi
, 4) << 4);
325 if ((t
= adi_get_bits(adi
, 4)) & ADI_FLAG_HAT
) adi
->hats
++;
327 adi
->length
= adi_get_bits(adi
, 10);
329 if (adi
->length
>= ADI_MAX_LENGTH
|| adi
->length
< ADI_MIN_LENGTH
) {
330 printk(KERN_WARNING
"adi: Bad data packet length (%d).\n", adi
->length
);
335 adi
->axes8
= adi_get_bits(adi
, 4);
336 adi
->buttons
= adi_get_bits(adi
, 6);
338 if (adi_get_bits(adi
, 6) != 8 && adi
->hats
) {
339 printk(KERN_WARNING
"adi: Other than 8-dir POVs not supported yet.\n");
344 adi
->buttons
+= adi_get_bits(adi
, 6);
345 adi
->hats
+= adi_get_bits(adi
, 4);
347 i
= adi_get_bits(adi
, 4);
349 if (t
& ADI_FLAG_10BIT
) {
350 adi
->axes10
= adi
->axes8
- i
;
354 t
= adi_get_bits(adi
, 4);
356 for (i
= 0; i
< t
; i
++)
357 adi
->cname
[i
] = adi_get_bits(adi
, 8);
360 t
= 8 + adi
->buttons
+ adi
->axes10
* 10 + adi
->axes8
* 8 + adi
->hats
* 4;
361 if (adi
->length
!= t
&& adi
->length
!= t
+ (t
& 1)) {
362 printk(KERN_WARNING
"adi: Expected length %d != data length %d\n", t
, adi
->length
);
382 static int adi_init_input(struct adi
*adi
, struct adi_port
*port
, int half
)
384 struct input_dev
*input_dev
;
385 char buf
[ADI_MAX_NAME_LENGTH
];
388 adi
->dev
= input_dev
= input_allocate_device();
392 t
= adi
->id
< ADI_ID_MAX
? adi
->id
: ADI_ID_MAX
;
394 snprintf(buf
, ADI_MAX_PHYS_LENGTH
, adi_names
[t
], adi
->id
);
395 snprintf(adi
->name
, ADI_MAX_NAME_LENGTH
, "Logitech %s [%s]", buf
, adi
->cname
);
396 snprintf(adi
->phys
, ADI_MAX_PHYS_LENGTH
, "%s/input%d", port
->gameport
->phys
, half
);
398 adi
->abs
= adi_abs
[t
];
399 adi
->key
= adi_key
[t
];
401 input_dev
->name
= adi
->name
;
402 input_dev
->phys
= adi
->phys
;
403 input_dev
->id
.bustype
= BUS_GAMEPORT
;
404 input_dev
->id
.vendor
= GAMEPORT_ID_VENDOR_LOGITECH
;
405 input_dev
->id
.product
= adi
->id
;
406 input_dev
->id
.version
= 0x0100;
407 input_dev
->dev
.parent
= &port
->gameport
->dev
;
409 input_set_drvdata(input_dev
, port
);
411 input_dev
->open
= adi_open
;
412 input_dev
->close
= adi_close
;
414 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
) | BIT_MASK(EV_ABS
);
416 for (i
= 0; i
< adi
->axes10
+ adi
->axes8
+ (adi
->hats
+ (adi
->pad
!= -1)) * 2; i
++)
417 set_bit(adi
->abs
[i
], input_dev
->absbit
);
419 for (i
= 0; i
< adi
->buttons
; i
++)
420 set_bit(adi
->key
[i
], input_dev
->keybit
);
425 static void adi_init_center(struct adi
*adi
)
432 for (i
= 0; i
< adi
->axes10
+ adi
->axes8
+ (adi
->hats
+ (adi
->pad
!= -1)) * 2; i
++) {
435 x
= input_abs_get_val(adi
->dev
, t
);
437 if (t
== ABS_THROTTLE
|| t
== ABS_RUDDER
|| adi
->id
== ADI_ID_WGPE
)
438 x
= i
< adi
->axes10
? 512 : 128;
441 input_set_abs_params(adi
->dev
, t
, 64, x
* 2 - 64, 2, 16);
442 else if (i
< adi
->axes10
+ adi
->axes8
)
443 input_set_abs_params(adi
->dev
, t
, 48, x
* 2 - 48, 1, 16);
445 input_set_abs_params(adi
->dev
, t
, -1, 1, 0, 0);
450 * adi_connect() probes for Logitech ADI joysticks.
453 static int adi_connect(struct gameport
*gameport
, struct gameport_driver
*drv
)
455 struct adi_port
*port
;
459 port
= kzalloc(sizeof(*port
), GFP_KERNEL
);
463 port
->gameport
= gameport
;
465 gameport_set_drvdata(gameport
, port
);
467 err
= gameport_open(gameport
, drv
, GAMEPORT_MODE_RAW
);
471 adi_init_digital(gameport
);
472 adi_read_packet(port
);
474 if (port
->adi
[0].ret
>= ADI_MIN_LEN_LENGTH
)
475 adi_move_bits(port
, adi_get_bits(port
->adi
, 10));
477 for (i
= 0; i
< 2; i
++) {
478 adi_id_decode(port
->adi
+ i
, port
);
480 if (!port
->adi
[i
].length
)
483 err
= adi_init_input(port
->adi
+ i
, port
, i
);
488 if (!port
->adi
[0].length
&& !port
->adi
[1].length
) {
493 gameport_set_poll_handler(gameport
, adi_poll
);
494 gameport_set_poll_interval(gameport
, 20);
496 msleep(ADI_INIT_DELAY
);
497 if (adi_read(port
)) {
498 msleep(ADI_DATA_DELAY
);
502 for (i
= 0; i
< 2; i
++)
503 if (port
->adi
[i
].length
> 0) {
504 adi_init_center(port
->adi
+ i
);
505 err
= input_register_device(port
->adi
[i
].dev
);
512 fail3
: while (--i
>= 0) {
513 if (port
->adi
[i
].length
> 0) {
514 input_unregister_device(port
->adi
[i
].dev
);
515 port
->adi
[i
].dev
= NULL
;
518 fail2
: for (i
= 0; i
< 2; i
++)
519 input_free_device(port
->adi
[i
].dev
);
520 gameport_close(gameport
);
521 fail1
: gameport_set_drvdata(gameport
, NULL
);
526 static void adi_disconnect(struct gameport
*gameport
)
529 struct adi_port
*port
= gameport_get_drvdata(gameport
);
531 for (i
= 0; i
< 2; i
++)
532 if (port
->adi
[i
].length
> 0)
533 input_unregister_device(port
->adi
[i
].dev
);
534 gameport_close(gameport
);
535 gameport_set_drvdata(gameport
, NULL
);
539 static struct gameport_driver adi_drv
= {
543 .description
= DRIVER_DESC
,
544 .connect
= adi_connect
,
545 .disconnect
= adi_disconnect
,
548 module_gameport_driver(adi_drv
);