[Pommed-commits] r376 - in trunk: . pommed
jblache at alioth.debian.org
jblache at alioth.debian.org
Fri Nov 16 18:31:15 UTC 2007
Author: jblache
Date: 2007-11-16 18:31:15 +0000 (Fri, 16 Nov 2007)
New Revision: 376
Modified:
trunk/ChangeLog
trunk/pommed/evdev.c
trunk/pommed/evdev.h
trunk/pommed/pommed.c
Log:
Rework the event handling in pommed.
- use epoll() instead of poll()
- use inotify to watch new event devices appear in /dev/input
This effectively fixes our everlasting issue of disappearing event devices after suspend and makes it possible to add event devices dynamically.
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2007-11-16 17:36:19 UTC (rev 375)
+++ trunk/ChangeLog 2007-11-16 18:31:15 UTC (rev 376)
@@ -7,6 +7,10 @@
- gpomme: remove audio-related code.
- pommed: partial support (ie. no LCD backlight yet) for the
MacBook3,1 (MacBook Core2 Duo Santa Rosa, November 2007).
+ - pommed: rework the event management. Use epoll() for event
+ polling instead of poll(). Use inotify to watch new event devices
+ appear in /dev/input. This effectively fixes our disappearing
+ event devices issues after suspend. YAY.
version 1.10:
- pommed: add a beeper feature as a substitute to the missing PC
Modified: trunk/pommed/evdev.c
===================================================================
--- trunk/pommed/evdev.c 2007-11-16 17:36:19 UTC (rev 375)
+++ trunk/pommed/evdev.c 2007-11-16 18:31:15 UTC (rev 376)
@@ -26,12 +26,14 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
-#include <poll.h>
#include <syslog.h>
#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
+
#include <linux/input.h>
#include "pommed.h"
@@ -57,25 +59,79 @@
#endif
-#define EVDEV_ADB_KBD (1 << 0)
-#define EVDEV_ADB_BUTTONS (1 << 1)
-#define EVDEV_USB_KBD1 (1 << 2)
-#define EVDEV_USB_KBD2 (1 << 3)
-#define EVDEV_APPLEIR (1 << 5)
-#define EVDEV_MOUSEEMU (1 << 6)
-#define EVDEV_SW_LID (1 << 7)
+/* Open event devices */
+static int ev_fds[EVDEV_MAX];
-#define EVDEV_NO_EVDEV 0
+/* epoll fd */
+static int epfd;
-/* evdev bitmask */
-static unsigned int evdevs;
+/* inotify fd */
+static int ifd;
-static struct pollfd *fds;
-static int nfds;
+static int
+evdev_try_add(int fd);
+static int
+evdev_add(int fd)
+{
+ int i;
+ int ret;
+
+ struct epoll_event epoll_ev;
+
+ for (i = 0; i < EVDEV_MAX; i++)
+ {
+ if (ev_fds[i] == -1)
+ {
+ ev_fds[i] = fd;
+
+ break;
+ }
+ }
+
+ epoll_ev.events = EPOLLIN;
+ epoll_ev.data.fd = fd;
+
+ ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epoll_ev);
+
+ if (ret < 0)
+ {
+ logmsg(LOG_ERR, "Could not add device to epoll: %s", strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+
static void
+evdev_remove(int fd)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < EVDEV_MAX; i++)
+ {
+ if (ev_fds[i] == fd)
+ {
+ ev_fds[i] = -1;
+
+ break;
+ }
+ }
+
+ ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
+
+ if (ret < 0)
+ logmsg(LOG_ERR, "Could not remove device from epoll: %s", strerror(errno));
+
+ close(fd);
+}
+
+
+static void
evdev_process_events(int fd)
{
int ret;
@@ -204,12 +260,7 @@
}
else if (ev.type == EV_SW)
{
- /* Lid switch
- *
- * Note: this can't tell you when the machine comes back from suspend,
- * because we close and reopen event devices at that time so we never
- * get to see the lid open event on resume.
- */
+ /* Lid switch */
if (ev.code == SW_LID)
{
if (ev.value)
@@ -229,44 +280,119 @@
}
-int
-evdev_event_loop(int *reopen)
+static void
+evdev_inotify_process(void)
{
int ret;
- int i;
+ int fd;
- ret = poll(fds, nfds, LOOP_TIMEOUT);
+ struct inotify_event ie[2];
+ char evdev[32];
+ ret = read(ifd, ie, sizeof(ie));
if (ret < 0)
{
- if (errno != EINTR)
+ logdebug("inotify read failed: %s\n", strerror(errno));
+
+ return;
+ }
+
+ /* ie[0] contains the inotify event information
+ * the memory space for ie[1] contains the name of the file
+ * see the inotify documentation
+ */
+
+ if ((ie[0].len == 0) || (ie[0].name == NULL))
+ {
+ logdebug("inotify event with no name\n");
+
+ return;
+ }
+
+ logdebug("Found new event device %s/%s\n", EVDEV_DIR, ie[0].name);
+
+ if (strncmp("event", ie[0].name, 5))
+ {
+ logdebug("Discarding %s/%s\n", EVDEV_DIR, ie[0].name);
+
+ return;
+ }
+
+ ret = snprintf(evdev, 32, "%s/%s", EVDEV_DIR, ie[0].name);
+
+ if ((ret <= 0) || (ret > 31))
+ return;
+
+ fd = open(evdev, O_RDWR);
+ if (fd < 0)
+ {
+ if (errno != ENOENT)
+ logmsg(LOG_WARNING, "Could not open %s: %s", evdev, strerror(errno));
+ }
+
+ evdev_try_add(fd);
+}
+
+
+int
+evdev_event_loop(void)
+{
+ int i;
+ int nfds;
+
+ int inotify = 0;
+
+ struct epoll_event events[MAX_EPOLL_EVENTS];
+
+ nfds = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, LOOP_TIMEOUT);
+
+ if (nfds < 0)
+ {
+ if (errno == EINTR)
+ return 1; /* pommed.c will go on with the events management */
+ else
{
- logmsg(LOG_ERR, "poll() error: %s", strerror(errno));
+ logmsg(LOG_ERR, "epoll_wait() error: %s", strerror(errno));
- return -2;
+ return -1; /* pommed.c will exit */
}
- else
- return -1;
}
- else if (ret != 0)
+
+
+ for (i = 0; i < nfds; i++)
{
- for (i = 0; i < nfds; i++)
+ /* some of the event devices cease to exist when suspending */
+ if (events[i].events & (EPOLLERR | EPOLLHUP))
{
- /* the event devices cease to exist when suspending */
- if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
+ logmsg(LOG_INFO, "Error condition signaled on event device");
+
+ if (events[i].data.fd == beep_info.fd)
+ logmsg(LOG_WARNING, "Beeper device lost; this should not happen");
+
+ if (events[i].data.fd == ifd)
{
- logmsg(LOG_WARNING, "Error condition signaled on evdev, reopening");
- *reopen = 1;
-
- return -1;
+ logmsg(LOG_WARNING, "inotify fd lost; this should not happen");
+ ifd = -1;
}
- if (fds[i].revents & POLLIN)
- evdev_process_events(fds[i].fd);
+ evdev_remove(events[i].data.fd);
+
+ continue;
}
+
+ if (events[i].events & EPOLLIN)
+ {
+ if (events[i].data.fd == ifd)
+ inotify = 1; /* defer inotify events processing */
+ else
+ evdev_process_events(events[i].data.fd);
+ }
}
- return ret;
+ if (inotify)
+ evdev_inotify_process();
+
+ return nfds;
}
@@ -287,7 +413,6 @@
{
logdebug(" -> ADB keyboard\n");
- evdevs |= EVDEV_ADB_KBD;
return 1;
}
@@ -295,7 +420,6 @@
{
logdebug(" -> ADB PowerBook buttons\n");
- evdevs |= EVDEV_ADB_BUTTONS;
return 1;
}
@@ -320,11 +444,6 @@
{
logdebug(" -> Fountain USB keyboard\n");
- if (evdevs & EVDEV_USB_KBD1)
- evdevs |= EVDEV_USB_KBD2;
- else
- evdevs |= EVDEV_USB_KBD1;
-
return 1;
}
@@ -348,10 +467,7 @@
{
logdebug(" -> Geyser USB keyboard\n");
- if (evdevs & EVDEV_USB_KBD1)
- evdevs |= EVDEV_USB_KBD2;
- else
- evdevs |= EVDEV_USB_KBD1;
+ kbd_set_fnmode();
return 1;
}
@@ -378,7 +494,6 @@
{
logdebug(" -> PMU LID switch\n");
- evdevs |= EVDEV_SW_LID;
return 1;
}
@@ -405,10 +520,7 @@
{
logdebug(" -> Geyser III USB keyboard\n");
- if (evdevs & EVDEV_USB_KBD1)
- evdevs |= EVDEV_USB_KBD2;
- else
- evdevs |= EVDEV_USB_KBD1;
+ kbd_set_fnmode();
return 1;
}
@@ -434,10 +546,7 @@
{
logdebug(" -> Geyser IV USB keyboard\n");
- if (evdevs & EVDEV_USB_KBD1)
- evdevs |= EVDEV_USB_KBD2;
- else
- evdevs |= EVDEV_USB_KBD1;
+ kbd_set_fnmode();
return 1;
}
@@ -463,10 +572,7 @@
{
logdebug(" -> Geyser IV-HF USB keyboard\n");
- if (evdevs & EVDEV_USB_KBD1)
- evdevs |= EVDEV_USB_KBD2;
- else
- evdevs |= EVDEV_USB_KBD1;
+ kbd_set_fnmode();
return 1;
}
@@ -491,7 +597,6 @@
{
logdebug(" -> Apple IR receiver\n");
- evdevs |= EVDEV_APPLEIR;
return 1;
}
@@ -514,7 +619,6 @@
{
logdebug(" -> ACPI LID switch\n");
- evdevs |= EVDEV_SW_LID;
return 1;
}
@@ -538,7 +642,6 @@
{
logdebug(" -> Mouseemu virtual keyboard\n");
- evdevs |= EVDEV_MOUSEEMU;
return 1;
}
@@ -546,185 +649,187 @@
}
-int
-evdev_open(void)
+static int
+evdev_try_add(int fd)
{
- int ret;
- int i, j;
-
- int fd[32];
-
unsigned short id[4];
unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
char devname[256];
- char evdev[32];
- evdevs = EVDEV_NO_EVDEV;
+ int ret;
- for (i = 0; i < EVDEV_MAX; i++)
+ devname[0] = '\0';
+ ioctl(fd, EVIOCGNAME(sizeof(devname)), devname);
+
+ logdebug("\nInvestigating evdev [%s]\n", devname);
+
+ ioctl(fd, EVIOCGID, id);
+
+ if ((!mops->evdev_identify(id))
+#ifndef __powerpc__
+ && !(appleir_cfg.enabled && evdev_is_appleir(id))
+#endif
+ && !(has_kbd_backlight() && evdev_is_lidswitch(id))
+ && !(evdev_is_mouseemu(id)))
{
- ret = snprintf(evdev, 32, "%s%d", EVDEV_BASE, i);
+ logdebug("Discarding evdev: bus 0x%04x, vid 0x%04x, pid 0x%04x\n", id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT]);
- if ((ret <= 0) || (ret > 31))
- return -1;
+ close(fd);
- fd[i] = open(evdev, O_RDWR);
- if (fd[i] < 0)
- {
- if (errno != ENOENT)
- logmsg(LOG_WARNING, "Could not open %s: %s", evdev, strerror(errno));
+ return -1;
+ }
- continue;
- }
+ memset(bit, 0, sizeof(bit));
- devname[0] = '\0';
- ioctl(fd[i], EVIOCGNAME(sizeof(devname)), devname);
- logdebug("\nInvestigating evdev %d [%s]\n", i, devname);
+ ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);
+ if (!test_bit(EV_KEY, bit[0]))
+ {
+ logdebug("evdev: no EV_KEY event type (not a keyboard)\n");
- ioctl(fd[i], EVIOCGID, id);
-
- if ((!mops->evdev_identify(id))
-#ifndef __powerpc__
- && !(appleir_cfg.enabled && evdev_is_appleir(id))
-#endif
- && !(has_kbd_backlight() && evdev_is_lidswitch(id))
- && !(evdev_is_mouseemu(id)))
+ if (!test_bit(EV_SW, bit[0]))
{
- logdebug("Discarding evdev %d: bus 0x%04x, vid 0x%04x, pid 0x%04x\n", i, id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT]);
+ logdebug("Discarding evdev: no EV_SW event type (not a switch)\n");
- close(fd[i]);
- fd[i] = -1;
+ close(fd);
- continue;
+ return -1;
}
+ }
+ else if (test_bit(EV_ABS, bit[0]))
+ {
+ logdebug("Discarding evdev with EV_ABS event type (mouse/trackpad)\n");
- memset(bit, 0, sizeof(bit));
+ close(fd);
- ioctl(fd[i], EVIOCGBIT(0, EV_MAX), bit[0]);
+ return -1;
+ }
- if (!test_bit(EV_KEY, bit[0]))
- {
- logdebug("evdev %d: no EV_KEY event type (not a keyboard)\n", i);
+ ret = evdev_add(fd);
- if (!test_bit(EV_SW, bit[0]))
- {
- logdebug("evdev %d: no EV_SW event type (not a switch)\n", i);
+ return ret;
+}
- close(fd[i]);
- fd[i] = -1;
- logdebug("Discarding evdev %d\n", i);
+static int
+evdev_inotify_init(void)
+{
+ int ret;
+ struct epoll_event epoll_ev;
- continue;
- }
- }
- else if (test_bit(EV_ABS, bit[0]))
- {
- logdebug("Discarding evdev %d with EV_ABS event type (mouse/trackpad)\n", i);
+ ifd = inotify_init();
+ if (ifd < 0)
+ {
+ logmsg(LOG_ERR, "Failed to initialize inotify: %s", strerror(errno));
- close(fd[i]);
- fd[i] = -1;
+ return -1;
+ }
- continue;
- }
+ ret = inotify_add_watch(ifd, EVDEV_DIR, IN_CREATE | IN_ONLYDIR);
+ if (ret < 0)
+ {
+ logmsg(LOG_ERR, "Failed to add inotify watch for %s: %s", EVDEV_DIR, strerror(errno));
- nfds++;
+ close(ifd);
+ ifd = -1;
+
+ return -1;
}
- logdebug("\nFound %d devices\n", nfds);
+ epoll_ev.events = EPOLLIN;
+ epoll_ev.data.fd = ifd;
- /* Allocate nfds pollfd structs + 1 for the beeper */
- fds = (struct pollfd *) malloc((nfds + 1) * sizeof(struct pollfd));
-
- if (fds == NULL)
+ ret = epoll_ctl(epfd, EPOLL_CTL_ADD, ifd, &epoll_ev);
+ if (ret < 0)
{
- for (i = 0; i < EVDEV_MAX; i++)
- {
- if (fd[i] > 0)
- close(fd[i]);
- }
+ logmsg(LOG_ERR, "Failed to add inotify fd to epoll: %s", strerror(errno));
- logmsg(LOG_ERR, "Out of memory for %d pollfd structs", nfds);
+ close(ifd);
return -1;
}
- j = 0;
- for (i = 0; i < EVDEV_MAX && j < nfds; i++)
+ return 0;
+}
+
+
+int
+evdev_init(void)
+{
+ int ret;
+ int i;
+
+ char evdev[32];
+
+ int ndevs;
+ int fd;
+
+ epfd = epoll_create(MAX_EPOLL_EVENTS);
+ if (epfd < 0)
{
- if (fd[i] < 0)
- continue;
+ logmsg(LOG_ERR, "Could not create epoll fd: %s", strerror(errno));
- fds[j].fd = fd[i];
- fds[j].events = POLLIN;
- j++;
+ return -1;
}
- ret = beep_open_device();
- if (ret == 0)
+ for (i = 0; i < EVDEV_MAX; i++)
{
- fds[j].fd = beep_info.fd;
- fds[j].events = POLLIN;
- nfds++;
+ ev_fds[i] = -1;
}
- return nfds;
-}
+ ndevs = 0;
+ for (i = 0; i < EVDEV_MAX; i++)
+ {
+ ret = snprintf(evdev, 32, "%s%d", EVDEV_BASE, i);
-void
-evdev_close(void)
-{
- int i;
+ if ((ret <= 0) || (ret > 31))
+ return -1;
- if (fds != NULL)
- {
- for (i = 0; i < nfds; i++)
+ fd = open(evdev, O_RDWR);
+ if (fd < 0)
{
- if (fds[i].fd == beep_info.fd)
- beep_close_device();
- else
- close(fds[i].fd);
+ if (errno != ENOENT)
+ logmsg(LOG_WARNING, "Could not open %s: %s", evdev, strerror(errno));
+
+ continue;
}
- free(fds);
+ if (evdev_try_add(fd) == 0)
+ ndevs++;
}
- fds = NULL;
+ logdebug("\nFound %d devices\n", ndevs);
+
+ /* Add the beeper device */
+ ret = beep_open_device();
+ if (ret == 0)
+ {
+ ret = evdev_add(beep_info.fd);
+
+ if (ret == 0)
+ ndevs++;
+ }
+
+ /* Initialize inotify */
+ evdev_inotify_init();
+
+ return ndevs;
}
-
-int
-evdev_reopen(void)
+void
+evdev_cleanup(void)
{
int i;
- unsigned int prev_evdevs = evdevs;
- evdev_close();
+ close(epfd);
- logdebug("Previous event devices: 0x%04x\n", prev_evdevs);
+ close(ifd);
- /* When resuming, we need to reopen event devices which
- * disappear at suspend time. We need to wait for udev to
- * recreate the device nodes.
- */
- for (i = 0; i < 50; i++)
+ for (i = 0; i < EVDEV_MAX; i++)
{
- usleep(500000);
-
- nfds = evdev_open();
-
- if (nfds > 0)
- {
- logdebug("Got event devices 0x%04x at iteration %d\n", evdevs, i);
-
- if (evdevs == prev_evdevs)
- break;
-
- /* We haven't got all the event devices we need */
- evdev_close();
- }
+ if (ev_fds[i] == beep_info.fd)
+ beep_close_device();
+ else
+ close(ev_fds[i]);
}
-
- return nfds;
}
Modified: trunk/pommed/evdev.h
===================================================================
--- trunk/pommed/evdev.h 2007-11-16 17:36:19 UTC (rev 375)
+++ trunk/pommed/evdev.h 2007-11-16 18:31:15 UTC (rev 376)
@@ -68,12 +68,15 @@
#define K_IR_MENU 0x8b
+#define EVDEV_DIR "/dev/input"
#define EVDEV_BASE "/dev/input/event"
#define EVDEV_MAX 32
+#define MAX_EPOLL_EVENTS 8
+
int
-evdev_event_loop(int *reopen);
+evdev_event_loop(void);
#ifdef __powerpc__
@@ -100,12 +103,9 @@
int
-evdev_open(void);
+evdev_init(void);
void
-evdev_close(void);
+evdev_cleanup(void);
-int
-evdev_reopen(void);
-
#endif /* !__EVDEV_H__ */
Modified: trunk/pommed/pommed.c
===================================================================
--- trunk/pommed/pommed.c 2007-11-16 17:36:19 UTC (rev 375)
+++ trunk/pommed/pommed.c 2007-11-16 18:31:15 UTC (rev 376)
@@ -641,7 +641,6 @@
FILE *pidfile;
- int reopen;
machine_type machine;
struct timeval tv_now;
@@ -739,15 +738,14 @@
exit(1);
}
- ret = evdev_open();
- if (ret < 1)
+ ret = evdev_init();
+ if (ret < 3)
{
logmsg(LOG_ERR, "No suitable event devices found");
exit(1);
}
- kbd_set_fnmode();
kbd_backlight_init();
ret = audio_init();
@@ -773,7 +771,7 @@
{
logmsg(LOG_ERR, "daemon() failed: %s", strerror(errno));
- evdev_close();
+ evdev_cleanup();
exit(-1);
}
@@ -784,7 +782,7 @@
{
logmsg(LOG_WARNING, "Could not open pidfile %s: %s", PIDFILE, strerror(errno));
- evdev_close();
+ evdev_cleanup();
exit(-1);
}
@@ -800,39 +798,16 @@
signal(SIGINT, sig_int_term_handler);
signal(SIGTERM, sig_int_term_handler);
- reopen = 0;
while (running)
{
- /* Attempt to reopen event devices, typically after resuming */
- if (reopen)
- {
- ret = evdev_reopen();
+ ret = evdev_event_loop();
- if (ret < 1)
- {
- logmsg(LOG_ERR, "No suitable event devices found (reopen)");
-
- break;
- }
-
- /* Re-set the keyboard mode
- * When we need to reopen the event devices, it means we've
- * just resumed from sleep
- */
- kbd_set_fnmode();
-
- reopen = 0;
- }
-
- ret = evdev_event_loop(&reopen);
-
gettimeofday(&tv_now, NULL);
if (ret < 0) /* error */
{
- if (ret == -2)
- break;
+ break;
}
else if (ret != 0)
{
@@ -880,7 +855,7 @@
mbpdbus_process_requests();
}
- evdev_close();
+ evdev_cleanup();
beep_cleanup();
More information about the Pommed-commits
mailing list