--- battstat/Makefile.in.orig	Mon Jan 24 20:20:49 2005
+++ battstat/Makefile.in	Mon Jan 24 20:22:02 2005
@@ -55,9 +55,10 @@
 PROGRAMS = $(libexec_PROGRAMS)
 am_battstat_applet_2_OBJECTS = properties.$(OBJEXT) \
 	battstat_applet.$(OBJEXT) power-management.$(OBJEXT) \
-	acpi-linux.$(OBJEXT)
+	acpi-freebsd.$(OBJEXT) acpi-linux.$(OBJEXT)
 battstat_applet_2_OBJECTS = $(am_battstat_applet_2_OBJECTS)
 am__DEPENDENCIES_1 =
+ACPIINC = @ACPIINC@
 @HAVE_LIBAPM_FALSE@@NEED_LIBAPM_TRUE@am__DEPENDENCIES_2 =  \
 @HAVE_LIBAPM_FALSE@@NEED_LIBAPM_TRUE@	apmlib/libapm.a
 battstat_applet_2_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@@ -66,6 +67,7 @@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/acpi-linux.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/acpi-freebsd.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/battstat_applet.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/power-management.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/properties.Po
@@ -336,6 +338,7 @@
 	$(GNOME_APPLETS_CFLAGS)			\
 	$(LIBGLADE_CFLAGS)			\
 	$(APMINC)				\
+	$(ACPIINC)				\
 	-DG_LOG_DOMAIN=\"battstat_applet\"
 
 battstat_applet_2_SOURCES = \
@@ -345,7 +348,9 @@
 	battstat_applet.c \
 	power-management.c \
 	acpi-linux.c \
-	acpi-linux.h
+	acpi-linux.h \
+	acpi-freebsd.c \
+	acpi-freebsd.h
 
 battstat_applet_2_LDADD = \
 		     $(GNOME_APPLETS_LIBS) \
@@ -439,6 +444,7 @@
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acpi-linux.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acpi-freebsd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/battstat_applet.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/power-management.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/properties.Po@am__quote@
--- battstat/battstat_applet.c.orig	Mon Jan 24 12:51:51 2005
+++ battstat/battstat_applet.c	Mon Jan 24 20:20:50 2005
@@ -953,6 +953,7 @@
 	"Seth Nickell <snickell@stanford.edu> (GNOME2 port)",
 	"Davyd Madeley <davyd@madeley.id.au>",
 	"Ryan Lortie <desrt@desrt.ca>",
+	"Joe Marcus Clarke <marcus@FreeBSD.org> (FreeBSD ACPI support)",
 	NULL
    };
 
--- battstat/properties.c.orig	Fri Jan 14 23:38:18 2005
+++ battstat/properties.c	Mon Mar 14 19:49:26 2005
@@ -27,7 +27,7 @@
 
 #include <stdio.h>
 
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) && defined(__i386__)
 #include <machine/apm_bios.h>
 #elif defined(__NetBSD__) || defined(__OpenBSD__)
 #include <sys/param.h>
@@ -61,6 +61,9 @@
 #include <panel-applet-gconf.h>
 /*#include <status-docklet.h>*/
 
+#if defined(__FreeBSD__) && !defined(__i386__)
+#include "acpi-freebsd.h"
+#endif
 #include "battstat.h"
 
 #ifndef gettext_noop
--- battstat/acpi-freebsd.c.orig	Sun Jul  3 16:00:01 2005
+++ battstat/acpi-freebsd.c	Sun Jul  3 16:23:26 2005
@@ -0,0 +1,280 @@
+/* battstat        A GNOME battery meter for laptops.
+ * Copyright (C) 2000 by Jrgen Pehrson <jp@spektr.eu.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ $Id: patch-battstat-acpi,v 1.13 2005/02/28 08:02:03 marcus Exp $
+ */
+
+/*
+ * ACPI battery functions for FreeBSD >= 5.2.
+ * September 2004 by Joe Marcus Clarke <marcus@FreeBSD.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __FreeBSD__
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#if defined(__i386__)
+#include <machine/apm_bios.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include <dev/acpica/acpiio.h>
+
+#include "acpi-freebsd.h"
+
+static gboolean
+update_ac_info(struct acpi_info * acpiinfo)
+{
+  int acline;
+  size_t len = sizeof(acline);
+
+  acpiinfo->ac_online = FALSE;
+
+  if (sysctlbyname(ACPI_ACLINE, &acline, &len, NULL, 0) == -1) {
+    return FALSE;
+  }
+
+  acpiinfo->ac_online = acline ? TRUE : FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+update_battery_info(struct acpi_info * acpiinfo)
+{
+  union acpi_battery_ioctl_arg battio;
+  int i;
+
+  /* We really don't have to do this here.  All of the relevant battery
+   * info can be obtained through sysctl.  However, one day, the rate
+   * may be useful to get time left to full charge.
+   */
+
+  for(i = BATT_MIN; i < BATT_MAX; i++) {
+    battio.unit = i;
+    if (ioctl(acpiinfo->acpifd, ACPIIO_CMBAT_GET_BIF, &battio) == -1) {
+      continue;
+    }
+
+    acpiinfo->max_capacity += battio.bif.lfcap;
+    acpiinfo->low_capacity += battio.bif.wcap;
+    acpiinfo->critical_capacity += battio.bif.lcap;
+  }
+
+  return TRUE;
+}
+
+gboolean
+acpi_freebsd_init(struct acpi_info * acpiinfo)
+{
+  int acpi_fd;
+  int event_fd;
+
+  g_assert(acpiinfo);
+
+  if (acpiinfo->acpifd == -1) {
+    acpi_fd = open(ACPIDEV, O_RDONLY);
+    if (acpi_fd >= 0) {
+      acpiinfo->acpifd = acpi_fd;
+    }
+    else {
+      acpiinfo->acpifd = -1;
+      return FALSE;
+    }
+  }
+
+  event_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (event_fd >= 0) {
+    struct sockaddr_un addr;
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, "/var/run/devd.pipe");
+    if (connect(event_fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
+      acpiinfo->event_fd = event_fd;
+      acpiinfo->event_inited = TRUE;
+      acpiinfo->channel = g_io_channel_unix_new(event_fd);
+    }
+    else {
+      close(event_fd);
+      acpiinfo->event_fd = -1;
+      acpiinfo->event_inited = FALSE;
+    }
+  }
+
+  update_battery_info(acpiinfo);
+  update_ac_info(acpiinfo);
+
+  return TRUE;
+}
+
+#define ACPI_EVENT_IGNORE	0
+#define ACPI_EVENT_AC		1
+#define ACPI_EVENT_BATTERY_INFO	2
+
+static int parse_acpi_event(GString *buffer)
+{
+   if (strstr(buffer->str, "system=ACPI")) {
+      if (strstr(buffer->str, "subsystem=ACAD"))
+        return ACPI_EVENT_AC;
+      if (strstr(buffer->str, "subsystem=CMBAT"))
+	return ACPI_EVENT_BATTERY_INFO;
+   }
+
+   return ACPI_EVENT_IGNORE;
+}
+
+void acpi_freebsd_update(struct acpi_info *acpiinfo)
+{
+   /* XXX This is needed for systems where devd does not have permissions
+    * to allow for event-driven updates.
+    */
+   update_ac_info(acpiinfo);
+   update_battery_info(acpiinfo);
+}
+
+gboolean acpi_process_event(struct acpi_info *acpiinfo, gboolean *read_error)
+{
+   gsize i;
+   int evt;
+   gboolean result = FALSE;
+   GString *buffer;
+   GIOStatus stat;
+   buffer = g_string_new(NULL);
+
+   *read_error = FALSE;
+   stat = g_io_channel_read_line_string(acpiinfo->channel, buffer, &i, NULL);
+
+   if (stat == G_IO_STATUS_ERROR || stat == G_IO_STATUS_EOF) {
+      *read_error = TRUE;
+      g_string_free(buffer, TRUE);
+      return FALSE;
+   }
+
+   evt = parse_acpi_event(buffer);
+   switch (evt) {
+      case ACPI_EVENT_AC:
+         update_ac_info(acpiinfo);
+	 result = TRUE;
+	 break;
+      case ACPI_EVENT_BATTERY_INFO:
+	 update_battery_info(acpiinfo);
+	 result = TRUE;
+	 break;
+   }
+
+   g_string_free(buffer, TRUE);
+   return result;
+}
+
+void
+acpi_freebsd_cleanup(struct acpi_info * acpiinfo)
+{
+  g_assert(acpiinfo);
+
+  if (acpiinfo->acpifd >= 0) {
+    close(acpiinfo->acpifd);
+    acpiinfo->acpifd = -1;
+  }
+
+  if (acpiinfo->event_fd >= 0) {
+    g_io_channel_unref(acpiinfo->channel);
+    close(acpiinfo->event_fd);
+    acpiinfo->event_fd = -1;
+  }
+}
+
+gboolean
+acpi_freebsd_read(struct apm_info *apminfo, struct acpi_info * acpiinfo)
+{
+  int time;
+  int life;
+  int acline;
+  int state;
+  size_t len;
+  int rate;
+  int remain;
+  union acpi_battery_ioctl_arg battio;
+  gboolean charging;
+  int i;
+
+  g_assert(acpiinfo);
+
+  charging = FALSE;
+
+  for(i = BATT_MIN; i < BATT_MAX; i++) {
+    battio.unit = i;
+    if (ioctl(acpiinfo->acpifd, ACPIIO_CMBAT_GET_BST, &battio) == -1) {
+      continue;
+    }
+
+    remain += battio.bst.cap;
+    rate += battio.bst.rate;
+  }
+
+  len = sizeof(time);
+  if (sysctlbyname(ACPI_TIME, &time, &len, NULL, 0) == -1) {
+    return FALSE;
+  }
+
+  len = sizeof(life);
+  if (sysctlbyname(ACPI_LIFE, &life, &len, NULL, 0) == -1) {
+    return FALSE;
+  }
+
+  len = sizeof(state);
+  if (sysctlbyname(ACPI_STATE, &state, &len, NULL, 0) == -1) {
+    return FALSE;
+  }
+
+  apminfo->ai_acline = acpiinfo->ac_online ? 1 : 0;
+  if (state & ACPI_BATT_STAT_CHARGING) {
+    apminfo->ai_batt_stat = 3;
+    charging = TRUE;
+  }
+  else if (state & ACPI_BATT_STAT_CRITICAL) {
+    /* Add a special check here since FreeBSD's ACPI interface will tell us
+     * when the battery is critical.
+     */
+    apminfo->ai_batt_stat = 2;
+  }
+  else {
+    apminfo->ai_batt_stat = remain < acpiinfo->low_capacity ? 1 : remain < acpiinfo->critical_capacity ? 2 : 0;
+  }
+  apminfo->ai_batt_life = life;
+  if (!charging) {
+    apminfo->ai_batt_time = time;
+  }
+  else if (charging && rate > 0) {
+    apminfo->ai_batt_time = (int) ((acpiinfo->max_capacity-remain)/(float)rate);
+  }
+  else
+    apminfo->ai_batt_time = -1;
+
+  return TRUE;
+}
+#endif
--- battstat/acpi-freebsd.h.orig	Sun Jul  3 16:00:01 2005
+++ battstat/acpi-freebsd.h	Sun Jul  3 16:23:56 2005
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004 by Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ACPI_FREEBSD_H__
+#define __ACPI_FREEBSD_H__
+
+#define ACPIDEV "/dev/acpi"
+
+#define BATT_MIN 0
+#define BATT_MAX 64
+
+#define ACPI_ACLINE "hw.acpi.acline"
+#define ACPI_TIME "hw.acpi.battery.time"
+#define ACPI_LIFE "hw.acpi.battery.life"
+#define ACPI_STATE "hw.acpi.battery.state"
+
+/* XXX: AMD64 does not have machine/apm_bios.h. */
+#if !defined(__i386__)
+struct apm_info {
+  guint    ai_acline;
+  guint    ai_batt_stat;
+  guint    ai_batt_life;
+  int      ai_batt_time;
+  guint    ai_status;
+};
+#endif
+
+struct acpi_info {
+  gboolean  ac_online;
+  gboolean  event_inited;
+  int       acpifd;
+  int       event_fd;
+  int       max_capacity;
+  int       low_capacity;
+  int       critical_capacity;
+  GIOChannel * channel;
+};
+
+gboolean acpi_freebsd_read(struct apm_info *apminfo, struct acpi_info * acpiinfo);
+void acpi_freebsd_update(struct acpi_info * acpiinfo);
+gboolean acpi_process_event(struct acpi_info * acpiinfo, gboolean *read_error);
+gboolean acpi_freebsd_init(struct acpi_info * acpiinfo);
+void acpi_freebsd_cleanup(struct acpi_info * acpiinfo);
+
+#endif /* __ACPI_FREEBSD_H__ */
--- battstat/power-management.c.orig	Sun Mar 20 05:20:55 2005
+++ battstat/power-management.c	Sun Jul  3 16:21:42 2005
@@ -73,12 +73,42 @@ static int pm_initialised;
  * the problem might be.  This error message is not to be freed.
  */
 
-#ifdef __FreeBSD__
-
+#if defined(__FreeBSD__)
+#if defined(__i386__)
 #include <machine/apm_bios.h>
+#endif
+#include "acpi-freebsd.h"
+
+static struct acpi_info acpiinfo;
+static gboolean using_acpi;
+static int acpi_count;
+static int acpiwatch;
+static struct apm_info apminfo;
+
+gboolean acpi_freebsd_read(struct apm_info *apminfo, struct acpi_info *acpiinfo);
 
 #define APMDEVICE "/dev/apm"
 
+static gboolean acpi_callback (GIOChannel * chan, GIOCondition cond, gpointer data)
+{
+   gboolean read_error;
+
+   if (cond & (G_IO_ERR | G_IO_HUP)) {
+     acpi_freebsd_cleanup(&acpiinfo);
+     return FALSE;
+   }
+
+   if (acpi_process_event(&acpiinfo, &read_error)) {
+     acpi_freebsd_read(&apminfo, &acpiinfo);
+   }
+   else if (read_error) {
+      acpi_freebsd_cleanup(&acpiinfo);
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
 static const char *
 apm_readinfo (BatteryStatus *status)
 {
@@ -86,32 +116,56 @@ apm_readinfo (BatteryStatus *status)
      FreeBSD.  Each time this functions is called (once every second)
      the APM device is opened, read from and then closed.
   */
-  struct apm_info apminfo;
   int fd;
 
   if (DEBUG) g_print("apm_readinfo() (FreeBSD)\n");
 
-  fd = open(APMDEVICE, O_RDONLY);
-  if (fd == -1)
-  {
-    pm_initialised = 0;
-    return ERR_OPEN_APMDEV;
+  if (using_acpi && (!acpiinfo.event_inited || acpiinfo.event_fd >= 0)) {
+    if (acpi_count <= 0) {
+      acpi_count = 30;
+      if (!acpiinfo.event_inited) {
+        acpi_freebsd_update(&acpiinfo);
+      }
+      acpi_freebsd_read(&apminfo, &acpiinfo);
+    }
+    acpi_count--;
+  }
+  else if (using_acpi && acpiinfo.event_inited) {
+    if (acpi_freebsd_init(&acpiinfo)) {
+        acpiwatch = g_io_add_watch (acpiinfo.channel,
+            G_IO_IN | G_IO_ERR | G_IO_HUP,
+	    acpi_callback, NULL);
+	acpi_freebsd_read(&apminfo, &acpiinfo);
+    }
   }
+  else {
+#if defined(__i386__)
+    fd = open(APMDEVICE, O_RDONLY);
+    if (fd == -1) {
+      return ERR_OPEN_APMDEV;
+    }
 
-  if (ioctl(fd, APMIO_GETINFO, &apminfo) == -1)
-    err(1, "ioctl(APMIO_GETINFO)");
+    if (ioctl(fd, APMIO_GETINFO, &apminfo) == -1)
+      err(1, "ioctl(APMIO_GETINFO)");
 
-  close(fd);
+      close(fd);
 
-  if(apminfo.ai_status == 0)
-    return ERR_APM_E;
+    if(apminfo.ai_status == 0)
+      return ERR_APM_E;
+#else
+    return ERR_OPEN_APMDEV;
+#endif
+  }
 
   status->present = TRUE;
   status->on_ac_power = apminfo.ai_acline ? 1 : 0;
   status->state = apminfo.ai_batt_stat;
   status->percent = apminfo.ai_batt_life;
   status->charging = (status->state == 3) ? TRUE : FALSE;
-  status->minutes = apminfo.ai_batt_time;
+  if (using_acpi)
+    status->minutes = apminfo.ai_batt_time;
+  else
+    status->minutes = (int) (apminfo.ai_batt_time/60.0);
 
   return NULL;
 }
@@ -339,6 +393,19 @@ power_management_initialise( void )
         G_IO_IN | G_IO_ERR | G_IO_HUP,
         acpi_callback, NULL);
   }
+#elif defined(__FreeBSD__)
+  if (acpi_freebsd_init(&acpiinfo)) {
+    using_acpi = TRUE;
+    acpi_count = 0;
+  }
+  else
+    using_acpi = FALSE;
+
+  if (using_acpi && acpiinfo.event_fd >= 0) {
+    acpiwatch = g_io_add_watch (acpiinfo.channel,
+	G_IO_IN | G_IO_ERR | G_IO_HUP,
+	acpi_callback, NULL);
+  }
 #endif
   pm_initialised = 1;
 
@@ -360,6 +427,13 @@ power_management_cleanup( void )
       g_source_remove(acpiwatch);
      acpiwatch = 0;
      acpi_linux_cleanup(&acpiinfo);
+  }
+#elif defined(__FreeBSD__)
+  if (using_acpi) {
+    if (acpiwatch != 0)
+      g_source_remove(acpiwatch);
+    acpiwatch = 0;
+    acpi_freebsd_cleanup(&acpiinfo);
   }
 #endif
 
