1 // SPDX-License-Identifier: GPL-2.0+ 2 /* fakekey.c 3 * Functions for simulating key presses. 4 * 5 * Copyright (C) 2010 the Speakup Team 6 */ 7 #include <linux/types.h> 8 #include <linux/slab.h> 9 #include <linux/preempt.h> 10 #include <linux/percpu.h> 11 #include <linux/input.h> 12 13 #include "speakup.h" 14 15 #define PRESSED 1 16 #define RELEASED 0 17 18 static DEFINE_PER_CPU(int, reporting_keystroke); 19 20 static struct input_dev *virt_keyboard; 21 22 int speakup_add_virtual_keyboard(void) 23 { 24 int err; 25 26 virt_keyboard = input_allocate_device(); 27 28 if (!virt_keyboard) 29 return -ENOMEM; 30 31 virt_keyboard->name = "Speakup"; 32 virt_keyboard->id.bustype = BUS_VIRTUAL; 33 virt_keyboard->phys = "speakup/input0"; 34 virt_keyboard->dev.parent = NULL; 35 36 __set_bit(EV_KEY, virt_keyboard->evbit); 37 __set_bit(KEY_DOWN, virt_keyboard->keybit); 38 39 err = input_register_device(virt_keyboard); 40 if (err) { 41 input_free_device(virt_keyboard); 42 virt_keyboard = NULL; 43 } 44 45 return err; 46 } 47 48 void speakup_remove_virtual_keyboard(void) 49 { 50 if (virt_keyboard) { 51 input_unregister_device(virt_keyboard); 52 virt_keyboard = NULL; 53 } 54 } 55 56 /* 57 * Send a simulated down-arrow to the application. 58 */ 59 void speakup_fake_down_arrow(void) 60 { 61 unsigned long flags; 62 63 /* disable keyboard interrupts */ 64 local_irq_save(flags); 65 /* don't change CPU */ 66 preempt_disable(); 67 68 __this_cpu_write(reporting_keystroke, true); 69 input_report_key(virt_keyboard, KEY_DOWN, PRESSED); 70 input_report_key(virt_keyboard, KEY_DOWN, RELEASED); 71 input_sync(virt_keyboard); 72 __this_cpu_write(reporting_keystroke, false); 73 74 /* reenable preemption */ 75 preempt_enable(); 76 /* reenable keyboard interrupts */ 77 local_irq_restore(flags); 78 } 79 80 /* 81 * Are we handling a simulated key press on the current CPU? 82 * Returns a boolean. 83 */ 84 bool speakup_fake_key_pressed(void) 85 { 86 return this_cpu_read(reporting_keystroke); 87 } 88