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 WK0701_DEBUG */
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
;
72 for (crc1
= crc2
= i
= 0; i
< 10; i
++) {
73 crc1
+= w
->buf
[i
] & 7;
74 crc2
+= (w
->buf
[i
] & 8) >> 3;
76 if ((w
->buf
[10] & 7) != (crc1
& 7))
78 if (((w
->buf
[10] & 8) >> 3) != (((crc1
>> 3) + crc2
) & 1))
80 for (crc1
= crc2
= 0, i
= 11; i
< 23; i
++) {
81 crc1
+= w
->buf
[i
] & 7;
82 crc2
+= (w
->buf
[i
] & 8) >> 3;
84 if ((w
->buf
[23] & 7) != (crc1
& 7))
86 if (((w
->buf
[23] & 8) >> 3) != (((crc1
>> 3) + crc2
) & 1))
88 val1
= ((w
->buf
[0] & 7) * 256 + w
->buf
[1] * 16 + w
->buf
[2]) >> 2;
89 val1
*= ((w
->buf
[0] >> 2) & 2) - 1; /* sign */
90 val2
= (w
->buf
[2] & 1) << 8 | (w
->buf
[3] << 4) | w
->buf
[4];
91 val2
*= (w
->buf
[2] & 2) - 1; /* sign */
92 val3
= ((w
->buf
[5] & 7) * 256 + w
->buf
[6] * 16 + w
->buf
[7]) >> 2;
93 val3
*= ((w
->buf
[5] >> 2) & 2) - 1; /* sign */
94 val4
= (w
->buf
[7] & 1) << 8 | (w
->buf
[8] << 4) | w
->buf
[9];
95 val4
*= (w
->buf
[7] & 2) - 1; /* sign */
96 val5
= ((w
->buf
[11] & 7) * 256 + w
->buf
[12] * 16 + w
->buf
[13]) >> 2;
97 val5
*= ((w
->buf
[11] >> 2) & 2) - 1; /* sign */
98 val6
= (w
->buf
[13] & 1) << 8 | (w
->buf
[14] << 4) | w
->buf
[15];
99 val6
*= (w
->buf
[13] & 2) - 1; /* sign */
100 val7
= ((w
->buf
[16] & 7) * 256 + w
->buf
[17] * 16 + w
->buf
[18]) >> 2;
101 val7
*= ((w
->buf
[16] >> 2) & 2) - 1; /*sign */
102 val8
= (w
->buf
[18] & 1) << 8 | (w
->buf
[19] << 4) | w
->buf
[20];
103 val8
*= (w
->buf
[18] & 2) - 1; /*sign */
107 int magic
, magic_bit
;
108 magic
= (w
->buf
[21] << 4) | w
->buf
[22];
109 magic_bit
= (w
->buf
[24] & 8) >> 3;
111 "walkera0701: %4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
112 val1
, val2
, val3
, val4
, val5
, val6
, val7
, val8
, magic
,
116 input_report_abs(w
->input_dev
, ABS_X
, val2
);
117 input_report_abs(w
->input_dev
, ABS_Y
, val1
);
118 input_report_abs(w
->input_dev
, ABS_Z
, val6
);
119 input_report_abs(w
->input_dev
, ABS_THROTTLE
, val3
);
120 input_report_abs(w
->input_dev
, ABS_RUDDER
, val4
);
121 input_report_abs(w
->input_dev
, ABS_MISC
, val7
);
122 input_report_key(w
->input_dev
, BTN_GEAR_DOWN
, val5
> 0);
125 static inline int read_ack(struct pardevice
*p
)
127 return parport_read_status(p
->port
) & 0x40;
130 /* falling edge, prepare to BIN value calculation */
131 static void walkera0701_irq_handler(void *handler_data
)
134 struct walkera_dev
*w
= handler_data
;
136 w
->irq_time
= ktime_to_ns(ktime_get());
137 pulse_time
= w
->irq_time
- w
->irq_lasttime
;
138 w
->irq_lasttime
= w
->irq_time
;
140 /* cancel timer, if in handler or active do resync */
141 if (unlikely(0 != hrtimer_try_to_cancel(&w
->timer
))) {
142 w
->counter
= NO_SYNC
;
146 if (w
->counter
< NO_SYNC
) {
148 pulse_time
-= BIN1_PULSE
;
149 w
->buf
[w
->counter
] = 8;
151 pulse_time
-= BIN0_PULSE
;
152 w
->buf
[w
->counter
] = 0;
154 if (w
->counter
== 24) { /* full frame */
155 walkera0701_parse_frame(w
);
156 w
->counter
= NO_SYNC
;
157 if (abs(pulse_time
- SYNC_PULSE
) < RESERVE
) /* new frame sync */
160 if ((pulse_time
> (ANALOG_MIN_PULSE
- RESERVE
)
161 && (pulse_time
< (ANALOG_MAX_PULSE
+ RESERVE
)))) {
162 pulse_time
-= (ANALOG_MIN_PULSE
- RESERVE
);
163 pulse_time
= (u32
) pulse_time
/ ANALOG_DELTA
; /* overtiping is safe, pulsetime < s32.. */
164 w
->buf
[w
->counter
++] |= (pulse_time
& 7);
166 w
->counter
= NO_SYNC
;
168 } else if (abs(pulse_time
- SYNC_PULSE
- BIN0_PULSE
) <
169 RESERVE
+ BIN1_PULSE
- BIN0_PULSE
) /* frame sync .. */
172 hrtimer_start(&w
->timer
, ktime_set(0, BIN_SAMPLE
), HRTIMER_MODE_REL
);
175 static enum hrtimer_restart
timer_handler(struct hrtimer
178 struct walkera_dev
*w
;
180 w
= container_of(handle
, struct walkera_dev
, timer
);
181 w
->ack
= read_ack(w
->pardevice
);
183 return HRTIMER_NORESTART
;
186 static int walkera0701_open(struct input_dev
*dev
)
188 struct walkera_dev
*w
= input_get_drvdata(dev
);
190 parport_enable_irq(w
->parport
);
194 static void walkera0701_close(struct input_dev
*dev
)
196 struct walkera_dev
*w
= input_get_drvdata(dev
);
198 parport_disable_irq(w
->parport
);
201 static int walkera0701_connect(struct walkera_dev
*w
, int parport
)
205 w
->parport
= parport_find_number(parport
);
206 if (w
->parport
== NULL
)
209 if (w
->parport
->irq
== -1) {
210 printk(KERN_ERR
"walkera0701: parport without interrupt\n");
215 w
->pardevice
= parport_register_device(w
->parport
, "walkera0701",
216 NULL
, NULL
, walkera0701_irq_handler
,
217 PARPORT_DEV_EXCL
, w
);
221 if (parport_negotiate(w
->pardevice
->port
, IEEE1284_MODE_COMPAT
))
224 if (parport_claim(w
->pardevice
))
227 w
->input_dev
= input_allocate_device();
231 input_set_drvdata(w
->input_dev
, w
);
232 w
->input_dev
->name
= "Walkera WK-0701 TX";
233 w
->input_dev
->phys
= w
->parport
->name
;
234 w
->input_dev
->id
.bustype
= BUS_PARPORT
;
236 /* TODO what id vendor/product/version ? */
237 w
->input_dev
->id
.vendor
= 0x0001;
238 w
->input_dev
->id
.product
= 0x0001;
239 w
->input_dev
->id
.version
= 0x0100;
240 w
->input_dev
->open
= walkera0701_open
;
241 w
->input_dev
->close
= walkera0701_close
;
243 w
->input_dev
->evbit
[0] = BIT(EV_ABS
) | BIT_MASK(EV_KEY
);
244 w
->input_dev
->keybit
[BIT_WORD(BTN_GEAR_DOWN
)] = BIT_MASK(BTN_GEAR_DOWN
);
246 input_set_abs_params(w
->input_dev
, ABS_X
, -512, 512, 0, 0);
247 input_set_abs_params(w
->input_dev
, ABS_Y
, -512, 512, 0, 0);
248 input_set_abs_params(w
->input_dev
, ABS_Z
, -512, 512, 0, 0);
249 input_set_abs_params(w
->input_dev
, ABS_THROTTLE
, -512, 512, 0, 0);
250 input_set_abs_params(w
->input_dev
, ABS_RUDDER
, -512, 512, 0, 0);
251 input_set_abs_params(w
->input_dev
, ABS_MISC
, -512, 512, 0, 0);
253 err
= input_register_device(w
->input_dev
);
257 hrtimer_init(&w
->timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_REL
);
258 w
->timer
.function
= timer_handler
;
262 input_free_device(w
->input_dev
);
264 parport_release(w
->pardevice
);
266 parport_unregister_device(w
->pardevice
);
268 parport_put_port(w
->parport
);
272 static void walkera0701_disconnect(struct walkera_dev
*w
)
274 hrtimer_cancel(&w
->timer
);
275 input_unregister_device(w
->input_dev
);
276 parport_release(w
->pardevice
);
277 parport_unregister_device(w
->pardevice
);
278 parport_put_port(w
->parport
);
281 static int __init
walkera0701_init(void)
283 return walkera0701_connect(&w_dev
, walkera0701_pp_no
);
286 static void __exit
walkera0701_exit(void)
288 walkera0701_disconnect(&w_dev
);
291 module_init(walkera0701_init
);
292 module_exit(walkera0701_exit
);