blob: ad64dae37d390afbca38cf23bf11abc9e508c335 [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <fcntl.h>
8#include <libtsm.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
Dominik Behr93899452014-08-18 22:16:21 -070014#include <sys/select.h>
15#include <errno.h>
16#include <libudev.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017#include "input.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070018#include "dbus_interface.h"
19#include "dbus.h"
20#include "util.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070021
Dominik Behr93899452014-08-18 22:16:21 -070022struct input_dev {
23 int fd;
24 char *path;
25};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070026
Dominik Behr93899452014-08-18 22:16:21 -070027struct {
28 struct udev *udev;
29 struct udev_monitor *udev_monitor;
30 int udev_fd;
31 unsigned int ndevs;
32 struct input_dev *devs;
David Sodmanbbcb0522014-09-19 10:34:07 -070033 dbus_t *dbus;
Dominik Behr93899452014-08-18 22:16:21 -070034} input = {
35 .udev = NULL,
36 .udev_monitor = NULL,
37 .udev_fd = -1,
38 .ndevs = 0,
39 .devs = NULL,
David Sodmanbbcb0522014-09-19 10:34:07 -070040 .dbus = NULL
Dominik Behr93899452014-08-18 22:16:21 -070041};
42
43static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070044{
Dominik Behr93899452014-08-18 22:16:21 -070045 int ret = 0, fd = -1;
46 /* for some reason every device has a null enumerations and notifications
47 of every device come with NULL string first */
48 if (!devname) {
49 ret = -EINVAL;
50 goto errorret;
51 }
52 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070053 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -070054 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070055
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070056 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
57
58 if (!ret) {
59 ioctl(fd, EVIOCGRAB, (void *) 0);
60 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -070061 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -070062 devname);
63 ret = -EBUSY;
64 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070065 }
66
Dominik Behr93899452014-08-18 22:16:21 -070067 struct input_dev *newdevs =
68 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
69 if (!newdevs) {
70 ret = -ENOMEM;
71 goto closefd;
72 }
73 input.devs = newdevs;
74 input.devs[input.ndevs].fd = fd;
75 input.devs[input.ndevs].path = strdup(devname);
76 if (!input.devs[input.ndevs].path) {
77 ret = -ENOMEM;
78 goto closefd;
79 }
80 input.ndevs++;
81
82 return fd;
83
84closefd:
85 close(fd);
86errorret:
87 return ret;
88}
89
90static void input_remove(const char *devname)
91{
92 if (!devname) {
93 return;
94 }
95 unsigned int u;
96 for (u = 0; u < input.ndevs; u++) {
97 if (!strcmp(devname, input.devs[u].path)) {
98 free(input.devs[u].path);
99 close(input.devs[u].fd);
100 input.ndevs--;
101 if (u != input.ndevs) {
102 input.devs[u] = input.devs[input.ndevs];
103 }
104 return;
105 }
106 }
107}
108
Dominik Behr93899452014-08-18 22:16:21 -0700109
110int input_init()
111{
112 input.udev = udev_new();
113 if (!input.udev)
114 return -ENOENT;
115 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
116 if (!input.udev_monitor) {
117 udev_unref(input.udev);
118 return -ENOENT;
119 }
120 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
121 NULL);
122 udev_monitor_enable_receiving(input.udev_monitor);
123 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
124
125 struct udev_enumerate *udev_enum;
126 struct udev_list_entry *devices, *deventry;
127 udev_enum = udev_enumerate_new(input.udev);
128 udev_enumerate_add_match_subsystem(udev_enum, "input");
129 udev_enumerate_scan_devices(udev_enum);
130 devices = udev_enumerate_get_list_entry(udev_enum);
131 udev_list_entry_foreach(deventry, devices) {
132 const char *syspath;
133 struct udev_device *dev;
134 syspath = udev_list_entry_get_name(deventry);
135 dev = udev_device_new_from_syspath(input.udev, syspath);
136 input_add(udev_device_get_devnode(dev));
137 udev_device_unref(dev);
138 }
139 udev_enumerate_unref(udev_enum);
140
141 if (!isatty(fileno(stdout)))
142 setbuf(stdout, NULL);
143
David Sodmanbbcb0522014-09-19 10:34:07 -0700144 if (input.ndevs == 0) {
145 LOG(ERROR, "No valid inputs for terminal");
146 exit(EXIT_SUCCESS);
147 }
148
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700149 return 0;
150}
151
152void input_close()
153{
Dominik Behr93899452014-08-18 22:16:21 -0700154 unsigned int u;
155 for (u = 0; u < input.ndevs; u++) {
156 free(input.devs[u].path);
157 close(input.devs[u].fd);
158 }
159 free(input.devs);
160 input.devs = NULL;
161 input.ndevs = 0;
162
163 udev_monitor_unref(input.udev_monitor);
164 input.udev_monitor = NULL;
165 udev_unref(input.udev);
166 input.udev = NULL;
167 input.udev_fd = -1;
168
David Sodmanbbcb0522014-09-19 10:34:07 -0700169 dbus_destroy(input.dbus);
170
171}
172
173void input_set_dbus(dbus_t* dbus)
174{
175 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700176}
177
Dominik Behr93899452014-08-18 22:16:21 -0700178int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700179{
Dominik Behr93899452014-08-18 22:16:21 -0700180 unsigned int u;
181 int max = -1;
182 for (u = 0; u < input.ndevs; u++) {
183 FD_SET(input.devs[u].fd, read_set);
184 FD_SET(input.devs[u].fd, exception_set);
185 if (input.devs[u].fd > max)
186 max = input.devs[u].fd;
187 }
188
189 FD_SET(input.udev_fd, read_set);
190 FD_SET(input.udev_fd, exception_set);
191 if (input.udev_fd > max)
192 max = input.udev_fd;
193 return max;
194}
195
196static void report_user_activity(void)
197{
David Sodmanbbcb0522014-09-19 10:34:07 -0700198 int activity_type = USER_ACTIVITY_OTHER;
Dominik Behr93899452014-08-18 22:16:21 -0700199
David Sodmanbbcb0522014-09-19 10:34:07 -0700200 dbus_method_call(input.dbus, kPowerManagerServiceName,
201 kPowerManagerServicePath,
202 kPowerManagerInterface,
203 kHandleUserActivityMethod,
204 &activity_type);
Dominik Behr93899452014-08-18 22:16:21 -0700205
David Sodmanbbcb0522014-09-19 10:34:07 -0700206 (void)dbus_message_new_method_call(kPowerManagerServiceName,
Dominik Behr93899452014-08-18 22:16:21 -0700207 kPowerManagerServicePath,
208 kPowerManagerInterface,
209 kHandleUserActivityMethod);
David Sodmanbbcb0522014-09-19 10:34:07 -0700210
Dominik Behr93899452014-08-18 22:16:21 -0700211}
212
213struct input_key_event *input_get_event(fd_set * read_set,
214 fd_set * exception_set)
215{
216 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700217 struct input_event ev;
218 int ret;
219
Dominik Behr93899452014-08-18 22:16:21 -0700220 if (FD_ISSET(input.udev_fd, exception_set)) {
221 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700222 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700223 }
224
Dominik Behr93899452014-08-18 22:16:21 -0700225 if (FD_ISSET(input.udev_fd, read_set)
226 && !FD_ISSET(input.udev_fd, exception_set)) {
227 /* we got an udev notification */
228 struct udev_device *dev =
229 udev_monitor_receive_device(input.udev_monitor);
230 if (dev) {
231 if (!strcmp("add", udev_device_get_action(dev))) {
232 input_add(udev_device_get_devnode(dev));
233 } else
234 if (!strcmp("remove", udev_device_get_action(dev)))
235 {
236 input_remove(udev_device_get_devnode(dev));
237 }
238 udev_device_unref(dev);
239 }
240 }
241
242 for (u = 0; u < input.ndevs; u++) {
243 if (FD_ISSET(input.devs[u].fd, read_set)
244 && !FD_ISSET(input.devs[u].fd, exception_set)) {
245 ret =
246 read(input.devs[u].fd, &ev, sizeof (struct input_event));
247 if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700248 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700249 (int) sizeof (struct input_event), ret);
250 return NULL;
251 }
252
253 if (ev.type == EV_KEY) {
254 struct input_key_event *event =
255 malloc(sizeof (*event));
256 event->code = ev.code;
257 event->value = ev.value;
258 report_user_activity();
259 return event;
260 }
261 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700262 }
263
264 return NULL;
265}
266
267void input_put_event(struct input_key_event *event)
268{
269 free(event);
270}
David Sodmanbbcb0522014-09-19 10:34:07 -0700271
272void input_grab()
273{
274 unsigned int i;
275 for (i = 0; i < input.ndevs; i++) {
276 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
277 }
278}
279
280void input_ungrab()
281{
282 unsigned int i;
283 for (i = 0; i < input.ndevs; i++) {
284 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
285 }
286}