[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