2022-04-17 22:20:18 +08:00
|
|
|
/*
|
|
|
|
* vkbd.c
|
|
|
|
*/
|
|
|
|
|
2022-04-05 23:51:54 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/input.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
|
|
|
|
#include "vinput.h"
|
|
|
|
|
|
|
|
#define VINPUT_KBD "vkbd"
|
|
|
|
#define VINPUT_RELEASE 0
|
|
|
|
#define VINPUT_PRESS 1
|
|
|
|
|
|
|
|
static unsigned short vkeymap[KEY_MAX];
|
|
|
|
|
|
|
|
static int vinput_vkbd_init(struct vinput *vinput)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Set up the input bitfield */
|
|
|
|
vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
|
|
|
vinput->input->keycodesize = sizeof(unsigned short);
|
|
|
|
vinput->input->keycodemax = KEY_MAX;
|
|
|
|
vinput->input->keycode = vkeymap;
|
|
|
|
|
|
|
|
for (i = 0; i < KEY_MAX; i++)
|
|
|
|
set_bit(vkeymap[i], vinput->input->keybit);
|
|
|
|
|
|
|
|
/* vinput will help us allocate new input device structure via
|
|
|
|
* input_allocate_device(). So, we can register it straightforwardly.
|
|
|
|
*/
|
|
|
|
return input_register_device(vinput->input);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len)
|
|
|
|
{
|
|
|
|
spin_lock(&vinput->lock);
|
|
|
|
len = snprintf(buff, len, "%+ld\n", vinput->last_entry);
|
|
|
|
spin_unlock(&vinput->lock);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
long key = 0;
|
|
|
|
short type = VINPUT_PRESS;
|
|
|
|
|
|
|
|
/* Determine which event was received (press or release)
|
|
|
|
* and store the state.
|
|
|
|
*/
|
|
|
|
if (buff[0] == '+')
|
|
|
|
ret = kstrtol(buff + 1, 10, &key);
|
|
|
|
else
|
|
|
|
ret = kstrtol(buff, 10, &key);
|
|
|
|
if (ret)
|
|
|
|
dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret);
|
|
|
|
spin_lock(&vinput->lock);
|
|
|
|
vinput->last_entry = key;
|
|
|
|
spin_unlock(&vinput->lock);
|
|
|
|
|
|
|
|
if (key < 0) {
|
|
|
|
type = VINPUT_RELEASE;
|
|
|
|
key = -key;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_info(&vinput->dev, "Event %s code %ld\n",
|
|
|
|
(type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key);
|
|
|
|
|
|
|
|
/* Report the state received to input subsystem. */
|
|
|
|
input_report_key(vinput->input, key, type);
|
|
|
|
/* Tell input subsystem that it finished the report. */
|
|
|
|
input_sync(vinput->input);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct vinput_ops vkbd_ops = {
|
|
|
|
.init = vinput_vkbd_init,
|
|
|
|
.send = vinput_vkbd_send,
|
|
|
|
.read = vinput_vkbd_read,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct vinput_device vkbd_dev = {
|
|
|
|
.name = VINPUT_KBD,
|
|
|
|
.ops = &vkbd_ops,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init vkbd_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < KEY_MAX; i++)
|
|
|
|
vkeymap[i] = i;
|
|
|
|
return vinput_register(&vkbd_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit vkbd_end(void)
|
|
|
|
{
|
|
|
|
vinput_unregister(&vkbd_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(vkbd_init);
|
|
|
|
module_exit(vkbd_end);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
|