2 * Parallel port to Walkera WK-0701 TX joystick
4 * Copyright (c) 2008 Peter Popovec
6 * More about driver: <file:Documentation/input/walkera0701.txt>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #define SYNC_PULSE 1306000
19 #define BIN0_PULSE 288000
20 #define BIN1_PULSE 438000
22 #define ANALOG_MIN_PULSE 318000
23 #define ANALOG_MAX_PULSE 878000
24 #define ANALOG_DELTA 80000
26 #define BIN_SAMPLE ((BIN0_PULSE + BIN1_PULSE) / 2)
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/parport.h>
33 #include <linux/input.h>
34 #include <linux/hrtimer.h>
36 MODULE_AUTHOR("Peter Popovec <popovec@fei.tuke.sk>");
37 MODULE_DESCRIPTION("Walkera WK-0701 TX as joystick");
38 MODULE_LICENSE("GPL");
40 static unsigned int walkera0701_pp_no
;
41 module_param_named(port
, walkera0701_pp_no
, int, 0);
42 MODULE_PARM_DESC(port
,
43 "Parallel port adapter for Walkera WK-0701 TX (default is 0)");
46 * For now, only one device is supported, if somebody need more devices, code
47 * can be expanded, one struct walkera_dev per device must be allocated and
48 * set up by walkera0701_connect (release of device by walkera0701_disconnect)
52 unsigned char buf
[25];
53 u64 irq_time
, irq_lasttime
;
57 struct input_dev
*input_dev
;
60 struct parport
*parport
;
61 struct pardevice
*pardevice
;
64 static struct walkera_dev w_dev
;
66 static inline void walkera0701_parse_frame(struct walkera_dev
*w
)
69 int val1
, val2
, val3
, val4
, val5
, val6
, val7
, val8
;
73 for (crc1
= crc2
= i
= 0; i
< 10; i
++) {
74 crc1
+= w
->buf
[i
] & 7;
75 crc2
+= (w
->buf
[i
] & 8) >> 3;
77 if ((w
->buf
[10] & 7) != (crc1
& 7))
79 if (((w
->buf
[10] & 8) >> 3) != (((crc1
>> 3) + crc2
) & 1))
81 for (crc1
= crc2
= 0, i
= 11; i
< 23; i
++) {
82 crc1
+= w
->buf
[i
] & 7;
83 crc2
+= (w
->buf
[i
] & 8) >> 3;
85 if ((w
->buf
[23] & 7) != (crc1
& 7))
87 if (((w
->buf
[23] & 8) >> 3) != (((crc1
>> 3) + crc2
) & 1))
89 val1
= ((w
->buf
[0] & 7) * 256 + w
->buf
[1] * 16 + w
->buf
[2]) >> 2;
90 val1
*= ((w
->buf
[0] >> 2) & 2) - 1; /* sign */
91 val2
= (w
->buf
[2] & 1) << 8 | (w
->buf
[3] << 4) | w
->buf
[4];
92 val2
*= (w
->buf
[2] & 2) - 1; /* sign */
93 val3
= ((w
->buf
[5] & 7) * 256 + w
->buf
[6] * 16 + w
->buf
[7]) >> 2;
94 val3
*= ((w
->buf
[5] >> 2) & 2) - 1; /* sign */
95 val4
= (w
->buf
[7] & 1) << 8 | (w
->buf
[8] << 4) | w
->buf
[9];
96 val4
*= (w
->buf
[7] & 2) - 1; /* sign */
97 val5
= ((w
->buf
[11] & 7) * 256 + w
->buf
[12] * 16 + w
->buf
[13]) >> 2;
98 val5
*= ((w
->buf
[11] >> 2) & 2) - 1; /* sign */
99 val6
= (w
->buf
[13] & 1) << 8 | (w
->buf
[14] << 4) | w
->buf
[15];
100 val6
*= (w
->buf
[13] & 2) - 1; /* sign */
101 val7
= ((w
->buf
[16] & 7) * 256 + w
->buf
[17] * 16 + w
->buf
[18]) >> 2;
102 val7
*= ((w
->buf
[16] >> 2) & 2) - 1; /*sign */
103 val8
= (w
->buf
[18] & 1) << 8 | (w
->buf
[19] << 4) | w
->buf
[20];
104 val8
*= (w
->buf
[18] & 2) - 1; /*sign */
106 magic
= (w
->buf
[21] << 4) | w
->buf
[22];
107 magic_bit
= (w
->buf
[24] & 8) >> 3;
108 pr_debug("%4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
109 val1
, val2
, val3
, val4
, val5
, val6
, val7
, val8
,
112 input_report_abs(w
->input_dev
, ABS_X
, val2
);
113 input_report_abs(w
->input_dev
, ABS_Y
, val1
);
114 input_report_abs(w
->input_dev
, ABS_Z
, val6
);
115 input_report_abs(w
->input_dev
, ABS_THROTTLE
, val3
);
116 input_report_abs(w
->input_dev
, ABS_RUDDER
, val4
);
117 input_report_abs(w
->input_dev
, ABS_MISC
, val7
);
118 input_report_key(w
->input_dev
, BTN_GEAR_DOWN
, val5
> 0);
121 static inline int read_ack(struct pardevice
*p
)
123 return parport_read_status(p
->port
) & 0x40;
126 /* falling edge, prepare to BIN value calculation */
127 static void walkera0701_irq_handler(void *handler_data
)
130 struct walkera_dev
*w
= handler_data
;
132 w
->irq_time
= ktime_to_ns(ktime_get());
133 pulse_time
= w
->irq_time
- w
->irq_lasttime
;
134 w
->irq_lasttime
= w
->irq_time
;
136 /* cancel timer, if in handler or active do resync */
137 if (unlikely(0 != hrtimer_try_to_cancel(&w
->timer
))) {
138 w
->counter
= NO_SYNC
;
142 if (w
->counter
< NO_SYNC
) {
144 pulse_time
-= BIN1_PULSE
;
145 w
->buf
[w
->counter
] = 8;
147 pulse_time
-= BIN0_PULSE
;
148 w
->buf
[w
->counter
] = 0;
150 if (w
->counter
== 24) { /* full frame */
151 walkera0701_parse_frame(w
);
152 w
->counter
= NO_SYNC
;
153 if (abs(pulse_time
- SYNC_PULSE
) < RESERVE
) /* new frame sync */
156 if ((pulse_time
> (ANALOG_MIN_PULSE
- RESERVE
)
157 && (pulse_time
< (ANALOG_MAX_PULSE
+ RESERVE
)))) {
158 pulse_time
-= (ANALOG_MIN_PULSE
- RESERVE
);
159 pulse_time
= (u32
) pulse_time
/ ANALOG_DELTA
; /* overtiping is safe, pulsetime < s32.. */
160 w
->buf
[w
->counter
++] |= (pulse_time
& 7);
162 w
->counter
= NO_SYNC
;
164 } else if (abs(pulse_time
- SYNC_PULSE
- BIN0_PULSE
) <
165 RESERVE
+ BIN1_PULSE
- BIN0_PULSE
) /* frame sync .. */
168 hrtimer_start(&w
->timer
, ktime_set(0, BIN_SAMPLE
), HRTIMER_MODE_REL
);
171 static enum hrtimer_restart
timer_handler(struct hrtimer
174 struct walkera_dev
*w
;
176 w
= container_of(handle
, struct walkera_dev
, timer
);
177 w
->ack
= read_ack(w
->pardevice
);
179 return HRTIMER_NORESTART
;
182 static int walkera0701_open(struct input_dev
*dev
)
184 struct walkera_dev
*w
= input_get_drvdata(dev
);
186 if (parport_claim(w
->pardevice
))
189 parport_enable_irq(w
->parport
);
193 static void walkera0701_close(struct input_dev
*dev
)
195 struct walkera_dev
*w
= input_get_drvdata(dev
);
197 parport_disable_irq(w
->parport
);
198 hrtimer_cancel(&w
->timer
);
200 parport_release(w
->pardevice
);
203 static int walkera0701_connect(struct walkera_dev
*w
, int parport
)
207 w
->parport
= parport_find_number(parport
);
209 pr_err("parport %d does not exist\n", parport
);
213 if (w
->parport
->irq
== -1) {
214 pr_err("parport %d does not have interrupt assigned\n",
217 goto err_put_parport
;
220 w
->pardevice
= parport_register_device(w
->parport
, "walkera0701",
221 NULL
, NULL
, walkera0701_irq_handler
,
222 PARPORT_DEV_EXCL
, w
);
224 pr_err("failed to register parport device\n");
226 goto err_put_parport
;
229 if (parport_negotiate(w
->pardevice
->port
, IEEE1284_MODE_COMPAT
)) {
230 pr_err("failed to negotiate parport mode\n");
232 goto err_unregister_device
;
235 hrtimer_init(&w
->timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_REL
);
236 w
->timer
.function
= timer_handler
;
238 w
->input_dev
= input_allocate_device();
240 pr_err("failed to allocate input device\n");
242 goto err_unregister_device
;
245 input_set_drvdata(w
->input_dev
, w
);
246 w
->input_dev
->name
= "Walkera WK-0701 TX";
247 w
->input_dev
->phys
= w
->parport
->name
;
248 w
->input_dev
->id
.bustype
= BUS_PARPORT
;
250 /* TODO what id vendor/product/version ? */
251 w
->input_dev
->id
.vendor
= 0x0001;
252 w
->input_dev
->id
.product
= 0x0001;
253 w
->input_dev
->id
.version
= 0x0100;
254 w
->input_dev
->dev
.parent
= w
->parport
->dev
;
255 w
->input_dev
->open
= walkera0701_open
;
256 w
->input_dev
->close
= walkera0701_close
;
258 w
->input_dev
->evbit
[0] = BIT(EV_ABS
) | BIT_MASK(EV_KEY
);
259 w
->input_dev
->keybit
[BIT_WORD(BTN_GEAR_DOWN
)] = BIT_MASK(BTN_GEAR_DOWN
);
261 input_set_abs_params(w
->input_dev
, ABS_X
, -512, 512, 0, 0);
262 input_set_abs_params(w
->input_dev
, ABS_Y
, -512, 512, 0, 0);
263 input_set_abs_params(w
->input_dev
, ABS_Z
, -512, 512, 0, 0);
264 input_set_abs_params(w
->input_dev
, ABS_THROTTLE
, -512, 512, 0, 0);
265 input_set_abs_params(w
->input_dev
, ABS_RUDDER
, -512, 512, 0, 0);
266 input_set_abs_params(w
->input_dev
, ABS_MISC
, -512, 512, 0, 0);
268 error
= input_register_device(w
->input_dev
);
270 pr_err("failed to register input device\n");
271 goto err_free_input_dev
;
277 input_free_device(w
->input_dev
);
278 err_unregister_device
:
279 parport_unregister_device(w
->pardevice
);
281 parport_put_port(w
->parport
);
285 static void walkera0701_disconnect(struct walkera_dev
*w
)
287 input_unregister_device(w
->input_dev
);
288 parport_unregister_device(w
->pardevice
);
289 parport_put_port(w
->parport
);
292 static int __init
walkera0701_init(void)
294 return walkera0701_connect(&w_dev
, walkera0701_pp_no
);
297 static void __exit
walkera0701_exit(void)
299 walkera0701_disconnect(&w_dev
);
302 module_init(walkera0701_init
);
303 module_exit(walkera0701_exit
);