-
Notifications
You must be signed in to change notification settings - Fork 0
/
event-input.c
4375 lines (3586 loc) · 125 KB
/
event-input.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @file event-input.c
* /dev/input event provider for the Mode Control Entity
* <p>
* Copyright (c) 2004 - 2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (c) 2013 - 2020 Jolla Ltd.
* Copyright (c) 2020 Open Mobile Platform LLC.
* <p>
* @author David Weinehall <[email protected]>
* @author Ismo Laitinen <[email protected]>
* @author Tapio Rantala <[email protected]>
* @author Santtu Lakkala <[email protected]>
* @author Jukka Turunen <[email protected]>
* @author Mika Laitio <[email protected]>
* @author Robin Burchell <[email protected]>
* @author Simo Piiroinen <[email protected]>
*
* mce is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* mce is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mce. If not, see <http://www.gnu.org/licenses/>.
*/
#include "event-input.h"
#include "mce.h"
#include "mce-log.h"
#include "mce-io.h"
#include "mce-lib.h"
#include "mce-conf.h"
#include "mce-dbus.h"
#ifdef ENABLE_DOUBLETAP_EMULATION
# include "mce-setting.h"
#endif
#include "mce-sensorfw.h"
#include "multitouch.h"
#include "evdev.h"
#include <mce/dbus-names.h>
#include <mce/mode-names.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
/* ========================================================================= *
* CONSTANTS
* ========================================================================= */
#ifndef SW_CAMERA_LENS_COVER
/** Input layer code for the camera lens cover switch */
# define SW_CAMERA_LENS_COVER 0x09
#endif
#ifndef SW_KEYPAD_SLIDE
/** Input layer code for the keypad slide switch */
# define SW_KEYPAD_SLIDE 0x0a
#endif
#ifndef SW_FRONT_PROXIMITY
/** Input layer code for the front proximity sensor switch */
# define SW_FRONT_PROXIMITY 0x0b
#endif
#ifndef KEY_CAMERA_FOCUS
/** Input layer code for the camera focus button */
# define KEY_CAMERA_FOCUS 0x0210
#endif
#ifndef FF_STATUS_CNT
# ifdef FF_STATUS_MAX
# define FF_STATUS_CNT (FF_STATUS_MAX+1)
# else
# define FF_STATUS_CNT 0
# endif
#endif
#ifndef PWR_CNT
# ifdef PWR_MAX
# define PWR_CNT (PWR_MAX+1)
# else
# define PWR_CNT 0
# endif
#endif
/* ========================================================================= *
* DATA TYPES AND FUNCTION PROTOTYPES
* ========================================================================= */
/* ------------------------------------------------------------------------- *
* GPIO_KEYS -- N900 camera focus key enable/disable policy
* ------------------------------------------------------------------------- */
static void evin_gpio_init (void);
static void evin_gpio_key_enable (unsigned key);
static void evin_gpio_key_disable (unsigned key);
/* ------------------------------------------------------------------------- *
* EVENT_MAPPING -- translate EV_SW events kernel sends to what mce expects
* ------------------------------------------------------------------------- */
/** Structure for holding evdev event translation data
*/
typedef struct
{
/** Event that kernel is emitting */
struct input_event em_kernel_emits;
/** Event mce is expecting to see */
struct input_event em_mce_expects;
} evin_event_mapping_t;
static int evin_event_mapping_guess_event_type (const char *event_code_name);
static bool evin_event_mapping_parse_event (struct input_event *ev, const char *event_code_name);
static bool evin_event_mapping_parse_config (evin_event_mapping_t *self, const char *kernel_emits, const char *mce_expects);
static bool evin_event_mapping_apply (const evin_event_mapping_t *self, struct input_event *ev);
static int evin_event_mapper_rlookup_switch (int expected_by_mce);
static void evin_event_mapper_translate_event (struct input_event *ev);
static void evin_event_mapper_init (void);
static void evin_event_mapper_quit (void);
/* ------------------------------------------------------------------------- *
* EVDEVBITS
* ------------------------------------------------------------------------- */
/** Calculate how many elements an array of longs bitmap needs to
* have enough space for bc items */
#define EVIN_EVDEVBITS_LEN(bc) (((bc)+LONG_BIT-1)/LONG_BIT)
/** Supported codes for one evdev event type
*/
typedef struct
{
/** event type */
int type;
/** event code count for this type */
int cnt;
/** bitmask of supported event codes */
unsigned long bit[0];
} evin_evdevbits_t;
static evin_evdevbits_t *evin_evdevbits_create (int type);
static void evin_evdevbits_delete (evin_evdevbits_t *self);
static int evin_evdevbits_probe (evin_evdevbits_t *self, int fd);
static void evin_evdevbits_clear (evin_evdevbits_t *self);
static int evin_evdevbits_test (const evin_evdevbits_t *self, int bit);
/* ------------------------------------------------------------------------- *
* EVDEVINFO
* ------------------------------------------------------------------------- */
/** Supported event types and codes for an evdev device node
*/
typedef struct
{
/** Array of bitmasks for supported event types */
evin_evdevbits_t *mask[EV_CNT];
} evin_evdevinfo_t;
static int evin_evdevinfo_list_has_entry (const int *list, int entry);
static evin_evdevinfo_t *evin_evdevinfo_create (void);
static void evin_evdevinfo_delete (evin_evdevinfo_t *self);
static int evin_evdevinfo_probe (evin_evdevinfo_t *self, int fd);
static int evin_evdevinfo_has_type (const evin_evdevinfo_t *self, int type);
static int evin_evdevinfo_has_types (const evin_evdevinfo_t *self, const int *types);
static int evin_evdevinfo_has_code (const evin_evdevinfo_t *self, int type, int code);
static int evin_evdevinfo_has_codes (const evin_evdevinfo_t *self, int type, const int *codes);
static int evin_evdevinfo_match_types_ex (const evin_evdevinfo_t *self, const int *types_req, const int *types_ign);
static int evin_evdevinfo_match_types (const evin_evdevinfo_t *self, const int *types);
static int evin_evdevinfo_match_codes_ex (const evin_evdevinfo_t *self, int type, const int *codes, const int *codes_ign);
static int evin_evdevinfo_match_codes (const evin_evdevinfo_t *self, int type, const int *codes);
static bool evin_evdevinfo_is_volumekey_default (const evin_evdevinfo_t *self);
static bool evin_evdevinfo_is_volumekey_hammerhead (const evin_evdevinfo_t *self);
static bool evin_evdevinfo_is_volumekey (const evin_evdevinfo_t *self);
static bool evin_evdevinfo_is_keyboard (const evin_evdevinfo_t *self);
/* ------------------------------------------------------------------------- *
* EVDEVTYPE
* ------------------------------------------------------------------------- */
/** Types of use MCE can have for evdev input devices
*/
typedef enum {
/** Sensors that might look like touch but should be ignored */
EVDEV_REJECT,
/** Touch screen to be tracked and processed */
EVDEV_TOUCH,
/** Mouse to be tracked and processed */
EVDEV_MOUSE,
/** Keys etc that mce needs to track and process */
EVDEV_INPUT,
/** Keys etc that mce itself does not need, tracked only for
* detecting user activity */
EVDEV_ACTIVITY,
/** The rest, mce does not track these */
EVDEV_IGNORE,
/** Button like touch device */
EVDEV_DBLTAP,
/** Proximity sensor */
EVDEV_PS,
/** Ambient light sensor */
EVDEV_ALS,
/** Volume key device */
EVDEV_VOLKEY,
/** Keyboard device */
EVDEV_KEYBOARD,
/** Device type was not explicitly set in configuration */
EVDEV_UNKNOWN,
} evin_evdevtype_t;
static const char *evin_evdevtype_repr (evin_evdevtype_t type);
static evin_evdevtype_t evin_evdevtype_parse (const char *name);
static evin_evdevtype_t evin_evdevtype_from_info (evin_evdevinfo_t *info);
/* ------------------------------------------------------------------------- *
* DOUBLETAP_EMULATION
* ------------------------------------------------------------------------- */
#ifdef ENABLE_DOUBLETAP_EMULATION
static void evin_doubletap_setting_cb (GConfClient *const client, const guint id, GConfEntry *const entry, gpointer const data);
#endif // ENABLE_DOUBLETAP_EMULATION
/* ------------------------------------------------------------------------- *
* INI_FILE_HELPERS
* ------------------------------------------------------------------------- */
static bool evio_is_valid_key_char(int ch);
static char *evio_sanitize_key_name(const char *name);
/* ------------------------------------------------------------------------- *
* EVDEV_IO_MONITORING
* ------------------------------------------------------------------------- */
/** Cached capabilities and type of monitored evdev input device */
typedef struct
{
/** Device name as reported by the driver */
char *ex_name;
/** Cached device node capabilities */
evin_evdevinfo_t *ex_info;
/** Device type from mce point of view */
evin_evdevtype_t ex_type;
/** Name of device that provides keypad slide state*/
gchar *ex_sw_keypad_slide;
/** State data for multitouch/mouse input devices */
mt_state_t *ex_mt_state;
} evin_iomon_extra_t;
static void evin_iomon_extra_delete_cb (void *aptr);
static evin_iomon_extra_t *evin_iomon_extra_create (int fd, const char *name);
// common rate limited activity generation
static void evin_iomon_generate_activity (struct input_event *ev, bool cooked, bool raw);
// event handling by device type
static bool evin_iomon_sw_gestures_allowed (void);
static gboolean evin_iomon_touchscreen_cb (mce_io_mon_t *iomon, gpointer data, gsize bytes_read);
static gboolean evin_iomon_evin_doubletap_cb (mce_io_mon_t *iomon, gpointer data, gsize bytes_read);
static gboolean evin_iomon_keypress_cb (mce_io_mon_t *iomon, gpointer data, gsize bytes_read);
static gboolean evin_iomon_activity_cb (mce_io_mon_t *iomon, gpointer data, gsize bytes_read);
// add/remove devices
static void evin_iomon_device_delete_cb (mce_io_mon_t *iomon);
static void evin_iomon_device_rem_all (void);
static void evin_iomon_device_add (const gchar *path);
static void evin_iomon_device_update (const gchar *path, gboolean add);
static mce_io_mon_t*evin_iomon_lookup_device (const char *name);
static void evin_iomon_device_iterate (evin_evdevtype_t type, GFunc func, gpointer data);
// check initial switch event states
static void evin_iomon_switch_states_update_iter_cb (gpointer io_monitor, gpointer user_data);
static void evin_iomon_switch_states_update (void);
static void evin_iomon_keyboard_state_update_iter_cb (gpointer io_monitor, gpointer user_data);
static void evin_iomon_keyboard_state_update (void);
static void evin_iomon_mouse_state_update_iter_cb (gpointer io_monitor, gpointer user_data);
static void evin_iomon_mouse_state_update (void);
// start/stop io monitoring
static bool evin_iomon_init (void);
static void evin_iomon_quit (void);
/* ------------------------------------------------------------------------- *
* EVDEV_DIRECTORY_MONITORING
* ------------------------------------------------------------------------- */
static void evin_devdir_monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data);
static bool evin_devdir_monitor_init (void);
static void evin_devdir_monitor_quit (void);
/* ------------------------------------------------------------------------- *
* TOUCHSTATE_MONITORING
* ------------------------------------------------------------------------- */
static void evin_touchstate_iomon_iter_cb (gpointer data, gpointer user_data);
static gboolean evin_touchstate_update_cb (gpointer aptr);
static void evin_touchstate_cancel_update (void);
static void evin_touchstate_schedule_update (void);
/* ------------------------------------------------------------------------- *
* INPUT_GRAB -- GENERIC EVDEV INPUT GRAB STATE MACHINE
* ------------------------------------------------------------------------- */
/** Event input policy state */
typedef enum
{
/** Initial value */
EVIN_STATE_UNKNOWN = 0,
/** Input events can be processed normally */
EVIN_STATE_ENABLED = 1,
/** Input events should be ignored */
EVIN_STATE_DISABLED = 2,
} evin_state_t;
static const char *evin_state_repr(evin_state_t state);
static const char *evin_state_to_dbus(evin_state_t state);
typedef struct evin_input_grab_t evin_input_grab_t;
/** State information for generic input grabbing state machine */
struct evin_input_grab_t
{
/** State machine instance name */
const char *ig_name;
/** Current policy decision */
evin_state_t ig_state;
/** Currently touched/down */
bool ig_touching;
/** Was touched/down, delaying release */
bool ig_touched;
/** Input grab is wanted */
bool ig_want_grab;
/** Input grab is allowed */
bool ig_allow_grab;
/** Input grab should be active */
bool ig_have_grab;
/** Input grab is active */
bool ig_real_grab;
/** Delayed release timer */
guint ig_release_id;
/** Delayed release delay */
int ig_release_ms;
/** Callback for notifying grab status changes */
void (*ig_grab_changed_cb)(evin_input_grab_t *self, bool have_grab);
/** Callback for additional release polling */
bool (*ig_release_verify_cb)(evin_input_grab_t *self);
/** Callback for broadcasting policy changes */
void (*ig_state_changed_cb)(evin_input_grab_t *self);
};
static void evin_input_grab_reset (evin_input_grab_t *self);
static gboolean evin_input_grab_release_cb (gpointer aptr);
static void evin_input_grab_start_release_timer (evin_input_grab_t *self);
static void evin_input_grab_cancel_release_timer (evin_input_grab_t *self);
static void evin_input_grab_rethink (evin_input_grab_t *self);
static void evin_input_grab_set_touching (evin_input_grab_t *self, bool touching);
static void evin_input_grab_request_grab (evin_input_grab_t *self, bool want_grab);
static void evin_input_grab_allow_grab (evin_input_grab_t *self, bool allow_grab);
static void evin_input_grab_iomon_cb (gpointer data, gpointer user_data);
/* ------------------------------------------------------------------------- *
* TS_GRAB -- TOUCHSCREEN EVDEV INPUT GRAB STATE MACHINE
* ------------------------------------------------------------------------- */
static void evin_ts_grab_set_led_raw (bool enabled);
static gboolean evin_ts_grab_set_led_cb (gpointer aptr);
static void evin_ts_grab_set_led (bool enabled);
static void evin_ts_grab_rethink_led (void);
static void evin_ts_grab_set_active (gboolean grab);
static bool evin_ts_grab_poll_palm_detect (evin_input_grab_t *ctrl);
static void evin_ts_grab_changed (evin_input_grab_t *ctrl, bool grab);
static void evin_ts_policy_changed (evin_input_grab_t *ctrl);
static void evin_ts_grab_setting_cb (GConfClient *const client, const guint id, GConfEntry *const entry, gpointer const data);
static void evin_ts_grab_init (void);
static void evin_ts_grab_quit (void);
/* ------------------------------------------------------------------------- *
* KP_GRAB -- KEYPAD EVDEV INPUT GRAB STATE MACHINE
* ------------------------------------------------------------------------- */
static void evin_kp_grab_set_active (gboolean grab);
static void evin_kp_grab_changed (evin_input_grab_t *ctrl, bool grab);
static void evin_kp_policy_changed (evin_input_grab_t *ctrl);
static void evin_kp_grab_event_filter_cb (struct input_event *ev);
/* ------------------------------------------------------------------------- *
* DYNAMIC_SETTINGS
* ------------------------------------------------------------------------- */
static void evin_setting_input_grab_rethink (void);
static void evin_setting_cb (GConfClient *const gcc, const guint id, GConfEntry *const entry, gpointer const data);
static void evin_setting_init (void);
static void evin_setting_quit (void);
/* ------------------------------------------------------------------------- *
* DBUS_HOOKS
* ------------------------------------------------------------------------- */
static void evin_dbus_send_keypad_input_policy (DBusMessage *const req);
static gboolean evin_dbus_keypad_input_policy_get_req_cb(DBusMessage *const msg);
static void evin_dbus_send_touch_input_policy (DBusMessage *const req);
static gboolean evin_dbus_touch_input_policy_get_req_cb (DBusMessage *const msg);
static void evin_dbus_init (void);
static void evin_dbus_quit (void);
/* ------------------------------------------------------------------------- *
* EVIN_DATAPIPE
* ------------------------------------------------------------------------- */
static void evin_datapipe_submode_cb (gconstpointer data);
static void evin_datapipe_touch_grab_wanted_cb (gconstpointer data);
static void evin_datapipe_touch_detected_cb (gconstpointer data);
static void evin_datapipe_display_state_curr_cb (gconstpointer data);
static void evin_datapipe_keypad_grab_wanted_cb (gconstpointer data);
static void evin_datapipe_display_state_next_cb (gconstpointer data);
static void evin_datapipe_proximity_sensor_actual_cb(gconstpointer data);
static void evin_datapipe_lid_sensor_filtered_cb (gconstpointer data);
static void evin_datapipe_topmost_window_pid_cb (gconstpointer data);
static void evin_datapipe_call_state_cb (gconstpointer data);
static void evin_datapipe_interaction_expected_cb (gconstpointer data);
static void evin_datapipe_alarm_ui_state_cb (gconstpointer data);
static void evin_datapipe_init (void);
static void evin_datapipe_quit (void);
/* ------------------------------------------------------------------------- *
* MODULE_INIT
* ------------------------------------------------------------------------- */
gboolean mce_input_init (void);
void mce_input_exit (void);
/* ========================================================================= *
* EVIN_DATAPIPE
* ========================================================================= */
/** Cached submode: Initialized to invalid placeholder value */
static submode_t submode = MCE_SUBMODE_INVALID;
/** Cached current display state */
static display_state_t display_state_curr = MCE_DISPLAY_UNDEF;
/** Cached target display state */
static display_state_t display_state_next = MCE_DISPLAY_UNDEF;
/** Cached touch input policy state */
static bool touch_grab_wanted = false;
/** Cached keypad input policy state */
static bool keypad_grab_wanted = false;
/** Cached finger on touchscreen state */
static bool touch_detected = false;
/** Cached (raw) proximity sensor state */
static cover_state_t proximity_sensor_actual = COVER_UNDEF;
/** Cached (filtered) lid sensor state */
static cover_state_t lid_sensor_filtered = COVER_UNDEF;
/** Cached PID of process owning the topmost window on UI */
static int topmost_window_pid = -1;
/** Cached alarm state; assume no active alarms */
static alarm_ui_state_t alarm_ui_state = MCE_ALARM_UI_OFF_INT32;
/** Cached call state */
static call_state_t call_state = CALL_STATE_INVALID;
/** Cached Interaction expected state */
static bool interaction_expected = false;
/* ========================================================================= *
* GPIO_KEYS
* ========================================================================= */
/** Can GPIO key interrupts be disabled? */
static gboolean evin_gpio_key_disable_exists = FALSE;
/** Check if enable/disable controls for gpio keys exist
*/
static void
evin_gpio_init(void)
{
evin_gpio_key_disable_exists = (g_access(GPIO_KEY_DISABLE_PATH, W_OK) == 0);
}
/** Enable the specified GPIO key
*
* Non-existing or already enabled keys are silently ignored
*
* @param key The key to enable
*/
static void
evin_gpio_key_enable(unsigned key)
{
gchar *disabled_keys_old = NULL;
gchar *disabled_keys_new = NULL;
gulong *bitmask = NULL;
gsize bitmasklen;
if( !mce_read_string_from_file(GPIO_KEY_DISABLE_PATH, &disabled_keys_old) )
goto EXIT;
bitmasklen = (KEY_CNT / bitsize_of(*bitmask)) +
((KEY_CNT % bitsize_of(*bitmask)) ? 1 : 0);
bitmask = g_malloc0(bitmasklen * sizeof (*bitmask));
if( !string_to_bitfield(disabled_keys_old, &bitmask, bitmasklen) )
goto EXIT;
clear_bit(key, &bitmask);
if( !(disabled_keys_new = bitfield_to_string(bitmask, bitmasklen)) )
goto EXIT;
mce_write_string_to_file(GPIO_KEY_DISABLE_PATH, disabled_keys_new);
EXIT:
g_free(disabled_keys_old);
g_free(bitmask);
g_free(disabled_keys_new);
return;
}
/** Disable the specified GPIO key/switch
*
* non-existing or already disabled keys/switches are silently ignored
*
* @param key The key/switch to disable
*/
static void
evin_gpio_key_disable(unsigned key)
{
gchar *disabled_keys_old = NULL;
gchar *disabled_keys_new = NULL;
gulong *bitmask = NULL;
gsize bitmasklen;
if( !mce_read_string_from_file(GPIO_KEY_DISABLE_PATH, &disabled_keys_old) )
goto EXIT;
bitmasklen = (KEY_CNT / bitsize_of(*bitmask)) +
((KEY_CNT % bitsize_of(*bitmask)) ? 1 : 0);
bitmask = g_malloc0(bitmasklen * sizeof (*bitmask));
if( !string_to_bitfield(disabled_keys_old, &bitmask, bitmasklen) )
goto EXIT;
set_bit(key, &bitmask);
if( !(disabled_keys_new = bitfield_to_string(bitmask, bitmasklen)) )
goto EXIT;
mce_write_string_to_file(GPIO_KEY_DISABLE_PATH, disabled_keys_new);
EXIT:
g_free(disabled_keys_old);
g_free(bitmask);
g_free(disabled_keys_new);
return;
}
/** Disable/enable gpio keys based on submode changes
*
* @param data The submode stored in a pointer
*/
static void
evin_datapipe_submode_cb(gconstpointer data)
{
submode_t prev = submode;
submode = GPOINTER_TO_INT(data);
if( prev != submode )
mce_log(LL_DEBUG, "submode: %s", submode_change_repr(prev, submode));
/* If the tklock is enabled, disable the camera focus interrupts,
* since we don't use them anyway
*/
if( evin_gpio_key_disable_exists ) {
submode_t tklock_prev = (prev & MCE_SUBMODE_TKLOCK);
submode_t tklock_curr = (submode & MCE_SUBMODE_TKLOCK);
if( tklock_prev != tklock_curr ) {
if( tklock_curr )
evin_gpio_key_disable(KEY_CAMERA_FOCUS);
else
evin_gpio_key_enable(KEY_CAMERA_FOCUS);
}
}
}
/* ========================================================================= *
* EVENT_MAPPING
* ========================================================================= */
/** Guess event type from name of the event code
*
* @param event_code_name name of the event e.g. "SW_KEYPAD_SLIDE"
*
* @return event type id e.g. EV_SW, or -1 if unknown
*/
static int
evin_event_mapping_guess_event_type(const char *event_code_name)
{
int etype = -1;
if( !event_code_name )
goto EXIT;
/* We are interested only in EV_KEY and EV_SW events */
if( !strncmp(event_code_name, "KEY_", 4) )
etype = EV_KEY;
else if( !strncmp(event_code_name, "BTN_", 4) )
etype = EV_KEY;
else if( !strncmp(event_code_name, "SW_", 3) )
etype = EV_SW;
EXIT:
return etype;
}
/** Fill in event type and code based on name of the event code
*
* @param event_code_name name of the event e.g. "SW_KEYPAD_SLIDE"
*
* @return true on success, or false on failure
*/
static bool
evin_event_mapping_parse_event(struct input_event *ev, const char *event_code_name)
{
bool success = false;
int etype = evin_event_mapping_guess_event_type(event_code_name);
if( etype < 0 )
goto EXIT;
int ecode = evdev_lookup_event_code(etype, event_code_name);
if( ecode < 0 )
goto EXIT;
ev->type = etype;
ev->code = ecode;
success = true;
EXIT:
return success;
}
/** Fill in event mapping structure from source and target event code names
*
* @param self pointer to a mapping structure to fill in
* @param kernel_emits name of the event kernel will be emitting
* @param mce_expects mame of the event mce is expecting instead
*
* @return true on success, or false on failure
*/
static bool
evin_event_mapping_parse_config(evin_event_mapping_t *self,
const char *kernel_emits,
const char *mce_expects)
{
bool success = false;
if( !evin_event_mapping_parse_event(&self->em_kernel_emits, kernel_emits) )
goto EXIT;
if( !evin_event_mapping_parse_event(&self->em_mce_expects, mce_expects) )
goto EXIT;
success = true;
EXIT:
return success;
}
/** Translate event if applicable
*
* @param self pointer to a mapping structure to use
* @param ev input event to modify
*
* @param true if event was modified, false otherwise
*/
static bool
evin_event_mapping_apply(const evin_event_mapping_t *self, struct input_event *ev)
{
bool applied = false;
if( self->em_kernel_emits.type != ev->type )
goto EXIT;
if( self->em_kernel_emits.code != ev->code )
goto EXIT;
mce_log(LL_DEBUG, "map: %s:%s -> %s:%s",
evdev_get_event_type_name(self->em_kernel_emits.type),
evdev_get_event_code_name(self->em_kernel_emits.type,
self->em_kernel_emits.code),
evdev_get_event_type_name(self->em_mce_expects.type),
evdev_get_event_code_name(self->em_mce_expects.type,
self->em_mce_expects.code));
ev->type = self->em_mce_expects.type;
ev->code = self->em_mce_expects.code;
applied = true;
EXIT:
return applied;
}
/** Lookup table for translatable events */
static evin_event_mapping_t *evin_event_mapper_lut = 0;
/** Number of entries in evin_event_mapper_lut */
static size_t evin_event_mapper_cnt = 0;
/** Reverse lookup switch kernel is emitting from switch mce is expecting
*
* Note: For use from event switch initial state evaluation only.
*
* @param expected_by_mce event code of SW_xxx kind mce expect to see
*
* @return event code of SW_xxx kind kernel might be sending
*/
static int
evin_event_mapper_rlookup_switch(int expected_by_mce)
{
/* Assume kernel emits events mce is expecting to see */
int emitted_by_kernel = expected_by_mce;
/* If emitted_by_kernel -> expected_by_mce mapping exist, use it */
for( size_t i = 0; i < evin_event_mapper_cnt; ++i ) {
evin_event_mapping_t *map = evin_event_mapper_lut + i;
if( map->em_kernel_emits.type != EV_SW )
continue;
if( map->em_mce_expects.type != EV_SW )
continue;
if( map->em_mce_expects.code != expected_by_mce )
continue;
emitted_by_kernel = map->em_kernel_emits.code;
goto EXIT;
}
/* But if there is rule for mapping the event for something
* else, it should be ignored instead of used as is */
for( size_t i = 0; i < evin_event_mapper_cnt; ++i ) {
evin_event_mapping_t *map = evin_event_mapper_lut + i;
if( map->em_kernel_emits.type != EV_SW )
continue;
if( map->em_mce_expects.type != EV_SW )
continue;
if( map->em_kernel_emits.code != expected_by_mce )
continue;
/* Assumption: SW_MAX is valid index for ioctl() probing,
* but is not an alias for anything that kernel
* would report.
*/
emitted_by_kernel = SW_MAX;
goto EXIT;
}
EXIT:
return emitted_by_kernel;
}
/** Translate event emitted by kernel to something mce is expecting to see
*
* @param ev Input event to translate
*/
static void
evin_event_mapper_translate_event(struct input_event *ev)
{
if( !ev )
goto EXIT;
/* Skip if there is no translation lookup table */
if( !evin_event_mapper_lut )
goto EXIT;
/* We want to process key and switch events, but under all
* potentially high frequency events should be skipped */
switch( ev->type ) {
case EV_KEY:
case EV_SW:
break;
default:
goto EXIT;
}
/* Try to find suitable mapping from lookup table */
for( size_t i = 0; i < evin_event_mapper_cnt; ++i ) {
evin_event_mapping_t *map = evin_event_mapper_lut + i;
if( evin_event_mapping_apply(map, ev) )
break;
}
EXIT:
return;
}
/** Initialize event translation lookup table
*/
static void
evin_event_mapper_init(void)
{
static const char grp[] = MCE_CONF_EVDEV_GROUP;
gchar **keys = 0;
gsize count = 0;
gsize valid = 0;
if( !mce_conf_has_group(grp) )
goto EXIT;
keys = mce_conf_get_keys(grp, &count);
if( !keys || !count )
goto EXIT;
evin_event_mapper_lut = calloc(count, sizeof *evin_event_mapper_lut);
for( gsize i = 0; i < count; ++i ) {
evin_event_mapping_t *map = evin_event_mapper_lut + valid;
const gchar *key = keys[i];
gchar *val = mce_conf_get_string(grp, key, 0);
if( val && evin_event_mapping_parse_config(map, key, val) )
++valid;
g_free(val);
}
evin_event_mapper_cnt = valid;
EXIT:
/* Remove also lookup table pointer if there are no entries */
if( !evin_event_mapper_cnt )
evin_event_mapper_quit();
g_strfreev(keys);
mce_log(LL_DEBUG, "EVDEV MAPS: %zd", evin_event_mapper_cnt);
return;
}
/** Release event translation lookup table
*/
static void
evin_event_mapper_quit(void)
{
free(evin_event_mapper_lut),
evin_event_mapper_lut = 0,
evin_event_mapper_cnt = 0;
}
/* ------------------------------------------------------------------------- *
* EVDEVBITS
* ------------------------------------------------------------------------- */
/** Create empty event code bitmap for one evdev event type
*
* @param type evdev event type
*
* @return evin_evdevbits_t object, or NULL for types not needed by mce
*/
static evin_evdevbits_t *
evin_evdevbits_create(int type)
{
evin_evdevbits_t *self = 0;
int cnt = 0;
switch( type ) {
case EV_SYN: cnt = EV_CNT; break;
case EV_KEY: cnt = KEY_CNT; break;
case EV_REL: cnt = REL_CNT; break;
case EV_ABS: cnt = ABS_CNT; break;
case EV_MSC: cnt = MSC_CNT; break;
case EV_SW: cnt = SW_CNT; break;
#if 0
case EV_LED: cnt = LED_CNT; break;
case EV_SND: cnt = SND_CNT; break;
case EV_REP: cnt = REP_CNT; break;
case EV_FF: cnt = FF_CNT; break;
case EV_PWR: cnt = PWR_CNT; break;
case EV_FF_STATUS: cnt = FF_STATUS_CNT; break;
#endif
default: break;
}
if( cnt > 0 ) {
int len = EVIN_EVDEVBITS_LEN(cnt);
self = g_malloc0(sizeof *self + len * sizeof *self->bit);
self->type = type;
self->cnt = cnt;
}
return self;
}
/** Delete evdev event code bitmap
*
* @param self evin_evdevbits_t object, or NULL
*/
static void
evin_evdevbits_delete(evin_evdevbits_t *self)
{
g_free(self);
}
/** Clear bits in evdev event code bitmap
*
* @param self evin_evdevbits_t object, or NULL
*/
static void
evin_evdevbits_clear(evin_evdevbits_t *self)
{
if( self ) {
int len = EVIN_EVDEVBITS_LEN(self->cnt);