162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* fakekey.c 362306a36Sopenharmony_ci * Functions for simulating key presses. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 the Speakup Team 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/preempt.h> 1062306a36Sopenharmony_ci#include <linux/percpu.h> 1162306a36Sopenharmony_ci#include <linux/input.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "speakup.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define PRESSED 1 1662306a36Sopenharmony_ci#define RELEASED 0 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic DEFINE_PER_CPU(int, reporting_keystroke); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic struct input_dev *virt_keyboard; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciint speakup_add_virtual_keyboard(void) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci int err; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci virt_keyboard = input_allocate_device(); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (!virt_keyboard) 2962306a36Sopenharmony_ci return -ENOMEM; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci virt_keyboard->name = "Speakup"; 3262306a36Sopenharmony_ci virt_keyboard->id.bustype = BUS_VIRTUAL; 3362306a36Sopenharmony_ci virt_keyboard->phys = "speakup/input0"; 3462306a36Sopenharmony_ci virt_keyboard->dev.parent = NULL; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci __set_bit(EV_KEY, virt_keyboard->evbit); 3762306a36Sopenharmony_ci __set_bit(KEY_DOWN, virt_keyboard->keybit); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci err = input_register_device(virt_keyboard); 4062306a36Sopenharmony_ci if (err) { 4162306a36Sopenharmony_ci input_free_device(virt_keyboard); 4262306a36Sopenharmony_ci virt_keyboard = NULL; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return err; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_civoid speakup_remove_virtual_keyboard(void) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci if (virt_keyboard) { 5162306a36Sopenharmony_ci input_unregister_device(virt_keyboard); 5262306a36Sopenharmony_ci virt_keyboard = NULL; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Send a simulated down-arrow to the application. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_civoid speakup_fake_down_arrow(void) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci unsigned long flags; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* disable keyboard interrupts */ 6462306a36Sopenharmony_ci local_irq_save(flags); 6562306a36Sopenharmony_ci /* don't change CPU */ 6662306a36Sopenharmony_ci preempt_disable(); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci __this_cpu_write(reporting_keystroke, true); 6962306a36Sopenharmony_ci input_report_key(virt_keyboard, KEY_DOWN, PRESSED); 7062306a36Sopenharmony_ci input_report_key(virt_keyboard, KEY_DOWN, RELEASED); 7162306a36Sopenharmony_ci input_sync(virt_keyboard); 7262306a36Sopenharmony_ci __this_cpu_write(reporting_keystroke, false); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* reenable preemption */ 7562306a36Sopenharmony_ci preempt_enable(); 7662306a36Sopenharmony_ci /* reenable keyboard interrupts */ 7762306a36Sopenharmony_ci local_irq_restore(flags); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * Are we handling a simulated key press on the current CPU? 8262306a36Sopenharmony_ci * Returns a boolean. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cibool speakup_fake_key_pressed(void) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci return this_cpu_read(reporting_keystroke); 8762306a36Sopenharmony_ci} 88