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