-
Notifications
You must be signed in to change notification settings - Fork 540
/
Copy pathvkbd.c
110 lines (87 loc) · 2.54 KB
/
vkbd.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
/*
* vkbd.c
*/
#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");