blob: f7c4a1fe6acb2f09b3b12839d3a6b6dff2607f93 [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>
17#include <dbus/dbus.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070018#include "input.h"
Dominik Behr93899452014-08-18 22:16:21 -070019#include "mini_power_manager.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070020
Dominik Behr93899452014-08-18 22:16:21 -070021struct input_dev {
22 int fd;
23 char *path;
24};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070025
Dominik Behr93899452014-08-18 22:16:21 -070026struct {
27 struct udev *udev;
28 struct udev_monitor *udev_monitor;
29 int udev_fd;
30 unsigned int ndevs;
31 struct input_dev *devs;
32 DBusConnection *dbus_conn;
33} input = {
34 .udev = NULL,
35 .udev_monitor = NULL,
36 .udev_fd = -1,
37 .ndevs = 0,
38 .devs = NULL,
39 .dbus_conn = NULL
40};
41
42static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070043{
Dominik Behr93899452014-08-18 22:16:21 -070044 int ret = 0, fd = -1;
45 /* for some reason every device has a null enumerations and notifications
46 of every device come with NULL string first */
47 if (!devname) {
48 ret = -EINVAL;
49 goto errorret;
50 }
51 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070052 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -070053 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070054
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070055 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
56
57 if (!ret) {
58 ioctl(fd, EVIOCGRAB, (void *) 0);
59 } else {
Dominik Behr93899452014-08-18 22:16:21 -070060 fprintf(stderr, "Evdev device %s grabbed by another process\n",
61 devname);
62 ret = -EBUSY;
63 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070064 }
65
Dominik Behr93899452014-08-18 22:16:21 -070066 struct input_dev *newdevs =
67 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
68 if (!newdevs) {
69 ret = -ENOMEM;
70 goto closefd;
71 }
72 input.devs = newdevs;
73 input.devs[input.ndevs].fd = fd;
74 input.devs[input.ndevs].path = strdup(devname);
75 if (!input.devs[input.ndevs].path) {
76 ret = -ENOMEM;
77 goto closefd;
78 }
79 input.ndevs++;
80
81 return fd;
82
83closefd:
84 close(fd);
85errorret:
86 return ret;
87}
88
89static void input_remove(const char *devname)
90{
91 if (!devname) {
92 return;
93 }
94 unsigned int u;
95 for (u = 0; u < input.ndevs; u++) {
96 if (!strcmp(devname, input.devs[u].path)) {
97 free(input.devs[u].path);
98 close(input.devs[u].fd);
99 input.ndevs--;
100 if (u != input.ndevs) {
101 input.devs[u] = input.devs[input.ndevs];
102 }
103 return;
104 }
105 }
106}
107
108static bool check_dbus_error(DBusError * err, const char *msg)
109{
110 if (dbus_error_is_set(err)) {
111 fprintf(stderr, "%s name:%s message:%s\n", msg, err->name,
112 err->message);
113 return true;
114 }
115 return false;
116}
117
118int input_init()
119{
120 input.udev = udev_new();
121 if (!input.udev)
122 return -ENOENT;
123 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
124 if (!input.udev_monitor) {
125 udev_unref(input.udev);
126 return -ENOENT;
127 }
128 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
129 NULL);
130 udev_monitor_enable_receiving(input.udev_monitor);
131 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
132
133 struct udev_enumerate *udev_enum;
134 struct udev_list_entry *devices, *deventry;
135 udev_enum = udev_enumerate_new(input.udev);
136 udev_enumerate_add_match_subsystem(udev_enum, "input");
137 udev_enumerate_scan_devices(udev_enum);
138 devices = udev_enumerate_get_list_entry(udev_enum);
139 udev_list_entry_foreach(deventry, devices) {
140 const char *syspath;
141 struct udev_device *dev;
142 syspath = udev_list_entry_get_name(deventry);
143 dev = udev_device_new_from_syspath(input.udev, syspath);
144 input_add(udev_device_get_devnode(dev));
145 udev_device_unref(dev);
146 }
147 udev_enumerate_unref(udev_enum);
148
149 if (!isatty(fileno(stdout)))
150 setbuf(stdout, NULL);
151
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700152 return 0;
153}
154
155void input_close()
156{
Dominik Behr93899452014-08-18 22:16:21 -0700157 unsigned int u;
158 for (u = 0; u < input.ndevs; u++) {
159 free(input.devs[u].path);
160 close(input.devs[u].fd);
161 }
162 free(input.devs);
163 input.devs = NULL;
164 input.ndevs = 0;
165
166 udev_monitor_unref(input.udev_monitor);
167 input.udev_monitor = NULL;
168 udev_unref(input.udev);
169 input.udev = NULL;
170 input.udev_fd = -1;
171
172 if (input.dbus_conn) {
173 /* FIXME - not sure what the right counterpart to
174 dbus_bus_get() is, unref documentation is rather
175 unclear. Not a big issue but it would be nice to
176 clean up properly here */
177 /* dbus_connection_unref(input.dbus_conn); */
178 input.dbus_conn = NULL;
179 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700180}
181
Dominik Behr93899452014-08-18 22:16:21 -0700182int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700183{
Dominik Behr93899452014-08-18 22:16:21 -0700184 unsigned int u;
185 int max = -1;
186 for (u = 0; u < input.ndevs; u++) {
187 FD_SET(input.devs[u].fd, read_set);
188 FD_SET(input.devs[u].fd, exception_set);
189 if (input.devs[u].fd > max)
190 max = input.devs[u].fd;
191 }
192
193 FD_SET(input.udev_fd, read_set);
194 FD_SET(input.udev_fd, exception_set);
195 if (input.udev_fd > max)
196 max = input.udev_fd;
197 return max;
198}
199
200static void report_user_activity(void)
201{
202 DBusError err;
203 dbus_error_init(&err);
204
205 if (!input.dbus_conn) {
206 input.dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
207 if (check_dbus_error(&err, "Cannot get dbus connection"))
208 return;
209 dbus_connection_set_exit_on_disconnect(input.dbus_conn, FALSE);
210 }
211
212 if (!dbus_bus_name_has_owner(input.dbus_conn, kPowerManagerServiceName, &err)) {
213 fprintf(stderr, "Power_manager not available on dbus!\n");
214 return;
215 }
216
217 DBusMessage *msg = NULL;
218 unsigned int activity_type = USER_ACTIVITY_OTHER;
219
220 msg = dbus_message_new_method_call(kPowerManagerServiceName,
221 kPowerManagerServicePath,
222 kPowerManagerInterface,
223 kHandleUserActivityMethod);
224 if (!msg)
225 return;
226 dbus_message_set_no_reply(msg, TRUE);
227 if (!dbus_message_append_args(msg,
228 DBUS_TYPE_UINT32, &activity_type,
229 DBUS_TYPE_INVALID)) {
230 dbus_message_unref(msg);
231 return;
232 }
233 if (!dbus_connection_send(input.dbus_conn, msg, NULL)) {
234 }
235 dbus_connection_flush(input.dbus_conn);
236 dbus_message_unref(msg);
237}
238
239struct input_key_event *input_get_event(fd_set * read_set,
240 fd_set * exception_set)
241{
242 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700243 struct input_event ev;
244 int ret;
245
Dominik Behr93899452014-08-18 22:16:21 -0700246 if (FD_ISSET(input.udev_fd, exception_set)) {
247 /* udev died on us? */
248 fprintf(stderr, "Exception on udev fd\n");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700249 }
250
Dominik Behr93899452014-08-18 22:16:21 -0700251 if (FD_ISSET(input.udev_fd, read_set)
252 && !FD_ISSET(input.udev_fd, exception_set)) {
253 /* we got an udev notification */
254 struct udev_device *dev =
255 udev_monitor_receive_device(input.udev_monitor);
256 if (dev) {
257 if (!strcmp("add", udev_device_get_action(dev))) {
258 input_add(udev_device_get_devnode(dev));
259 } else
260 if (!strcmp("remove", udev_device_get_action(dev)))
261 {
262 input_remove(udev_device_get_devnode(dev));
263 }
264 udev_device_unref(dev);
265 }
266 }
267
268 for (u = 0; u < input.ndevs; u++) {
269 if (FD_ISSET(input.devs[u].fd, read_set)
270 && !FD_ISSET(input.devs[u].fd, exception_set)) {
271 ret =
272 read(input.devs[u].fd, &ev, sizeof (struct input_event));
273 if (ret < (int) sizeof (struct input_event)) {
274 printf("expected %d bytes, got %d\n",
275 (int) sizeof (struct input_event), ret);
276 return NULL;
277 }
278
279 if (ev.type == EV_KEY) {
280 struct input_key_event *event =
281 malloc(sizeof (*event));
282 event->code = ev.code;
283 event->value = ev.value;
284 report_user_activity();
285 return event;
286 }
287 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700288 }
289
290 return NULL;
291}
292
293void input_put_event(struct input_key_event *event)
294{
295 free(event);
296}