import the FreeBSD backend

Add a backend for FreeBSD supporting AC power lines, batteries, and
lid state.
This commit is contained in:
Joe Marcus Clarke 2010-01-02 14:03:05 -05:00 committed by Richard Hughes
parent 725acd4d35
commit 131bc12a81
17 changed files with 2091 additions and 3 deletions

View file

@ -1,6 +1,8 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = devkit-power-gobject src doc tools policy po rules
SUBDIRS = devkit-power-gobject src doc tools policy po $(UDEV_RULES)
DIST_SUBDIRS = devkit-power-gobject src doc tools policy po rules
# Creating ChangeLog from git log (taken from cairo/Makefile.am):
ChangeLog: $(srcdir)/ChangeLog

View file

@ -149,11 +149,14 @@ dnl - Compile time default choice of backend
dnl ---------------------------------------------------------------------------
AC_ARG_WITH([backend],
AS_HELP_STRING([--with-backend=<option>],
[Default backend to use linux, dummy (dummy)]))
[Default backend to use linux, freebsd, dummy (dummy)]))
UDEV_RULES=
# default to a sane option
if test x$with_backend = x; then
if test -e /usr/include/gudev-1.0/gudev/gudev.h ; then
with_backend=linux
elif test -e /usr/include/dev/acpica/acpiio.h ; then
with_backend=freebsd
else
with_backend=dummy
fi
@ -170,11 +173,14 @@ if test x$with_backend = xlinux; then
dnl Check libusb also
AC_CHECK_HEADERS(usb.h, , [AC_MSG_ERROR([Can't find usb.h. Please install libusb.])])
AC_CHECK_LIB([usb], [usb_find_devices], [], [AC_MSG_ERROR([Can't use libusb.])])
UDEV_RULES="rules"
fi
AC_SUBST(UDEV_RULES)
# export to Makefile.am
AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$with_backend = xdummy])
AM_CONDITIONAL(BACKEND_TYPE_LINUX, [test x$with_backend = xlinux])
AM_CONDITIONAL(BACKEND_TYPE_FREEBSD, [test x$with_backend = xfreebsd])
dnl ---------------------------------------------------------------------------
dnl - Build self tests
@ -201,6 +207,7 @@ Makefile
devkit-power-gobject.pc
src/Makefile
src/dummy/Makefile
src/freebsd/Makefile
src/linux/Makefile
tools/Makefile
doc/Makefile

View file

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = dummy linux
SUBDIRS = dummy freebsd linux
INCLUDES = \
-I$(top_builddir)/src -I$(top_srcdir)/src \
@ -104,6 +104,12 @@ devkit_power_daemon_LDADD += \
dummy/libdkpshared.la
endif
if BACKEND_TYPE_FREEBSD
devkit_power_daemon_LDADD += \
freebsd/libdkpshared.la \
$(DEVKIT_POWER_LIBS)
endif
if BACKEND_TYPE_LINUX
devkit_power_daemon_LDADD += \
linux/libdkpshared.la \

45
src/freebsd/Makefile.am Normal file
View file

@ -0,0 +1,45 @@
## Process this file with automake to produce Makefile.in
INCLUDES = \
-I$(top_builddir)/src -I$(top_srcdir)/src \
-DEGG_LOG_FILE=\""$(DKP_LOG_DIR)/DeviceKit-power"\" \
-DEGG_VERBOSE="\"DKP_VERBOSE\"" \
-DEGG_LOGGING="\"DKP_LOGGING\"" \
-DEGG_CONSOLE="\"DKP_CONSOLE\"" \
-DDKP_COMPILATION \
-I$(top_srcdir)/devkit-power-gobject \
$(DBUS_GLIB_CFLAGS) \
$(POLKIT_CFLAGS) \
$(GLIB_CFLAGS)
if BACKEND_TYPE_FREEBSD
noinst_LTLIBRARIES = libdkpshared.la
endif
libdkpshared_la_SOURCES = \
dkp-acpi-native.c \
dkp-acpi-native.h \
dkp-backend-acpi.h \
dkp-backend.c \
dkp-devd.c \
dkp-devd.h \
dkp-device-supply.c \
dkp-device-supply.h \
dkp-native.c \
dkp-util.c \
dkp-util.h \
$(BUILT_SOURCES)
libdkpshared_la_CFLAGS = \
$(WARNINGFLAGS_C)
libdkpshared_la_LIBADD = \
-lkvm
EXTRA_DIST = \
dkp-acpi-native.vala \
TODO
clean-local :
rm -f *~

4
src/freebsd/TODO Normal file
View file

@ -0,0 +1,4 @@
FreeBSD doesn't have udev, so the udev rules can't be automatically applied.
However, they are useful in that they contain some needed battery recall
information. To that end, they should be incorporated into the FreeBSD
backend probably by adding them to a static array, or a hashtable.

View file

@ -0,0 +1,234 @@
/* dkp-acpi-native.c generated by valac, the Vala compiler
* generated from dkp-acpi-native.vala, do not modify */
#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
#define TYPE_DKP_ACPI_NATIVE (dkp_acpi_native_get_type ())
#define DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNative))
#define DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
#define IS_DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_DKP_ACPI_NATIVE))
#define IS_DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DKP_ACPI_NATIVE))
#define DKP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
typedef struct _DkpAcpiNative DkpAcpiNative;
typedef struct _DkpAcpiNativeClass DkpAcpiNativeClass;
typedef struct _DkpAcpiNativePrivate DkpAcpiNativePrivate;
#define _g_free0(var) (var = (g_free (var), NULL))
#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
#define _g_match_info_free0(var) ((var == NULL) ? NULL : (var = (g_match_info_free (var), NULL)))
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
struct _DkpAcpiNative {
GObject parent_instance;
DkpAcpiNativePrivate * priv;
};
struct _DkpAcpiNativeClass {
GObjectClass parent_class;
};
struct _DkpAcpiNativePrivate {
char* _driver;
gint _unit;
char* _path;
};
static gpointer dkp_acpi_native_parent_class = NULL;
GType dkp_acpi_native_get_type (void);
#define DKP_ACPI_NATIVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativePrivate))
enum {
DKP_ACPI_NATIVE_DUMMY_PROPERTY,
DKP_ACPI_NATIVE_DRIVER,
DKP_ACPI_NATIVE_UNIT,
DKP_ACPI_NATIVE_PATH
};
DkpAcpiNative* dkp_acpi_native_new (const char* path);
DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path);
DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit);
DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit);
const char* dkp_acpi_native_get_driver (DkpAcpiNative* self);
gint dkp_acpi_native_get_unit (DkpAcpiNative* self);
const char* dkp_acpi_native_get_path (DkpAcpiNative* self);
static void dkp_acpi_native_finalize (GObject* obj);
static void dkp_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec);
DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path) {
GError * _inner_error_;
DkpAcpiNative * self;
GRegex* r;
GMatchInfo* mi;
gboolean ret = FALSE;
char* _tmp9_;
g_return_val_if_fail (path != NULL, NULL);
_inner_error_ = NULL;
self = (DkpAcpiNative*) g_object_new (object_type, NULL);
r = NULL;
mi = NULL;
{
GRegex* _tmp0_;
GRegex* _tmp1_;
GMatchInfo* _tmp4_;
gboolean _tmp3_;
GMatchInfo* _tmp2_ = NULL;
_tmp0_ = g_regex_new ("dev\\.([^\\.])\\.(\\d+)", 0, 0, &_inner_error_);
if (_inner_error_ != NULL) {
if (_inner_error_->domain == G_REGEX_ERROR) {
goto __catch0_g_regex_error;
}
goto __finally0;
}
r = (_tmp1_ = _tmp0_, _g_regex_unref0 (r), _tmp1_);
ret = (_tmp3_ = g_regex_match (r, path, 0, &_tmp2_), mi = (_tmp4_ = _tmp2_, _g_match_info_free0 (mi), _tmp4_), _tmp3_);
if (ret) {
char* _tmp5_;
char* _tmp6_;
self->priv->_driver = (_tmp5_ = g_match_info_fetch (mi, 1), _g_free0 (self->priv->_driver), _tmp5_);
self->priv->_unit = atoi (_tmp6_ = g_match_info_fetch (mi, 2));
_g_free0 (_tmp6_);
} else {
char* _tmp7_;
self->priv->_driver = (_tmp7_ = NULL, _g_free0 (self->priv->_driver), _tmp7_);
self->priv->_unit = -1;
}
}
goto __finally0;
__catch0_g_regex_error:
{
GError * re;
re = _inner_error_;
_inner_error_ = NULL;
{
char* _tmp8_;
self->priv->_driver = (_tmp8_ = NULL, _g_free0 (self->priv->_driver), _tmp8_);
self->priv->_unit = -1;
_g_error_free0 (re);
}
}
__finally0:
if (_inner_error_ != NULL) {
_g_regex_unref0 (r);
_g_match_info_free0 (mi);
g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
g_clear_error (&_inner_error_);
return NULL;
}
self->priv->_path = (_tmp9_ = g_strdup (path), _g_free0 (self->priv->_path), _tmp9_);
_g_regex_unref0 (r);
_g_match_info_free0 (mi);
return self;
}
DkpAcpiNative* dkp_acpi_native_new (const char* path) {
return dkp_acpi_native_construct (TYPE_DKP_ACPI_NATIVE, path);
}
DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit) {
DkpAcpiNative * self;
char* _tmp0_;
char* _tmp1_;
g_return_val_if_fail (driver != NULL, NULL);
self = (DkpAcpiNative*) g_object_new (object_type, NULL);
self->priv->_driver = (_tmp0_ = g_strdup (driver), _g_free0 (self->priv->_driver), _tmp0_);
self->priv->_unit = unit;
self->priv->_path = (_tmp1_ = g_strdup_printf ("dev.%s.%i", self->priv->_driver, self->priv->_unit), _g_free0 (self->priv->_path), _tmp1_);
return self;
}
DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit) {
return dkp_acpi_native_construct_driver_unit (TYPE_DKP_ACPI_NATIVE, driver, unit);
}
const char* dkp_acpi_native_get_driver (DkpAcpiNative* self) {
const char* result;
g_return_val_if_fail (self != NULL, NULL);
result = self->priv->_driver;
return result;
}
gint dkp_acpi_native_get_unit (DkpAcpiNative* self) {
gint result;
g_return_val_if_fail (self != NULL, 0);
result = self->priv->_unit;
return result;
}
const char* dkp_acpi_native_get_path (DkpAcpiNative* self) {
const char* result;
g_return_val_if_fail (self != NULL, NULL);
result = self->priv->_path;
return result;
}
static void dkp_acpi_native_class_init (DkpAcpiNativeClass * klass) {
dkp_acpi_native_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, sizeof (DkpAcpiNativePrivate));
G_OBJECT_CLASS (klass)->get_property = dkp_acpi_native_get_property;
G_OBJECT_CLASS (klass)->finalize = dkp_acpi_native_finalize;
g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_DRIVER, g_param_spec_string ("driver", "driver", "driver", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_UNIT, g_param_spec_int ("unit", "unit", "unit", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_PATH, g_param_spec_string ("path", "path", "path", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
}
static void dkp_acpi_native_instance_init (DkpAcpiNative * self) {
self->priv = DKP_ACPI_NATIVE_GET_PRIVATE (self);
}
static void dkp_acpi_native_finalize (GObject* obj) {
DkpAcpiNative * self;
self = DKP_ACPI_NATIVE (obj);
_g_free0 (self->priv->_driver);
_g_free0 (self->priv->_path);
G_OBJECT_CLASS (dkp_acpi_native_parent_class)->finalize (obj);
}
GType dkp_acpi_native_get_type (void) {
static GType dkp_acpi_native_type_id = 0;
if (dkp_acpi_native_type_id == 0) {
static const GTypeInfo g_define_type_info = { sizeof (DkpAcpiNativeClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) dkp_acpi_native_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DkpAcpiNative), 0, (GInstanceInitFunc) dkp_acpi_native_instance_init, NULL };
dkp_acpi_native_type_id = g_type_register_static (G_TYPE_OBJECT, "DkpAcpiNative", &g_define_type_info, 0);
}
return dkp_acpi_native_type_id;
}
static void dkp_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
DkpAcpiNative * self;
self = DKP_ACPI_NATIVE (object);
switch (property_id) {
case DKP_ACPI_NATIVE_DRIVER:
g_value_set_string (value, dkp_acpi_native_get_driver (self));
break;
case DKP_ACPI_NATIVE_UNIT:
g_value_set_int (value, dkp_acpi_native_get_unit (self));
break;
case DKP_ACPI_NATIVE_PATH:
g_value_set_string (value, dkp_acpi_native_get_path (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}

View file

@ -0,0 +1,48 @@
/* dkp-acpi-native.h generated by valac, the Vala compiler, do not modify */
#ifndef __DKP_ACPI_NATIVE_H__
#define __DKP_ACPI_NATIVE_H__
#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
G_BEGIN_DECLS
#define TYPE_DKP_ACPI_NATIVE (dkp_acpi_native_get_type ())
#define DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNative))
#define DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
#define IS_DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_DKP_ACPI_NATIVE))
#define IS_DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DKP_ACPI_NATIVE))
#define DKP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
typedef struct _DkpAcpiNative DkpAcpiNative;
typedef struct _DkpAcpiNativeClass DkpAcpiNativeClass;
typedef struct _DkpAcpiNativePrivate DkpAcpiNativePrivate;
struct _DkpAcpiNative {
GObject parent_instance;
DkpAcpiNativePrivate * priv;
};
struct _DkpAcpiNativeClass {
GObjectClass parent_class;
};
GType dkp_acpi_native_get_type (void);
DkpAcpiNative* dkp_acpi_native_new (const char* path);
DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path);
DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit);
DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit);
const char* dkp_acpi_native_get_driver (DkpAcpiNative* self);
gint dkp_acpi_native_get_unit (DkpAcpiNative* self);
const char* dkp_acpi_native_get_path (DkpAcpiNative* self);
G_END_DECLS
#endif

View file

@ -0,0 +1,46 @@
public class DkpAcpiNative : Object {
private string? _driver;
private int _unit;
private string _path;
public string driver {
get { return _driver; }
}
public int unit {
get { return _unit; }
}
public string path {
get { return _path; }
}
public DkpAcpiNative (string path) {
Regex r;
MatchInfo mi;
bool ret;
try {
r = new Regex("dev\\.([^\\.])\\.(\\d+)");
ret = r.match(path, 0, out mi);
if (ret) {
_driver = mi.fetch(1);
_unit = mi.fetch(2).to_int();
} else {
_driver = null;
_unit = -1;
}
} catch (RegexError re) {
_driver = null;
_unit = -1;
}
_path = path;
}
public DkpAcpiNative.driver_unit (string driver, int unit) {
_driver = driver;
_unit = unit;
_path = "dev.%s.%i".printf (_driver, _unit);
}
}

View file

@ -0,0 +1,33 @@
/***************************************************************************
* CVSID: $Id$
*
* dkp-backend-acpi.h : define some backend objects
*
* Copyright (C) 2006, 2009 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifndef _DKP_BACKEND_ACPI_H
#define _DKP_BACKEND_ACPI_H
#include "config.h"
#include "dkp-devd.h"
extern DkpDevdHandler dkp_backend_acpi_devd_handler;
#endif /* _DKP_BACKEND_ACPI_H */

511
src/freebsd/dkp-backend.c Normal file
View file

@ -0,0 +1,511 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Joe Marcus Clarke <marcus@FreeBSD.org>
*
* Licensed under the GNU General Public License Version 2
*
* 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 Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <kvm.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "dkp-acpi-native.h"
#include "dkp-backend-acpi.h"
#include "dkp-devd.h"
#include "dkp-device-supply.h"
#include "dkp-util.h"
#include "egg-debug.h"
#include "dkp-backend.h"
#include "dkp-daemon.h"
#include "dkp-marshal.h"
#include "dkp-device.h"
#define DKP_BACKEND_REFRESH_TIMEOUT 30 /* seconds */
#define DKP_BACKEND_SUSPEND_COMMAND "/usr/sbin/zzz"
#define DKP_BACKEND_HIBERNATE_COMMAND "/usr/sbin/acpiconf -s 4"
static void dkp_backend_class_init (DkpBackendClass *klass);
static void dkp_backend_init (DkpBackend *backend);
static void dkp_backend_finalize (GObject *object);
static gboolean dkp_backend_refresh_devices (gpointer user_data);
static gboolean dkp_backend_acpi_devd_notify (DkpBackend *backend, const char *system, const char *subsystem, const char *type, const char *data);
static gboolean dkp_backend_create_new_device (DkpBackend *backend, DkpAcpiNative *native);
static void dkp_backend_lid_coldplug (DkpBackend *backend);
static gboolean dkp_backend_supports_sleep_state (const char *state);
#define DKP_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DKP_TYPE_BACKEND, DkpBackendPrivate))
struct DkpBackendPrivate
{
DkpDaemon *daemon;
DkpDeviceList *device_list;
GHashTable *handle_map;
guint poll_timer_id;
};
enum {
SIGNAL_DEVICE_ADDED,
SIGNAL_DEVICE_REMOVED,
SIGNAL_LAST
};
static guint signals [SIGNAL_LAST] = { 0 };
G_DEFINE_TYPE (DkpBackend, dkp_backend, G_TYPE_OBJECT)
static const char *handlers[] = {
"battery",
};
DkpDevdHandler dkp_backend_acpi_devd_handler = {
.notify = dkp_backend_acpi_devd_notify
};
/**
* dkp_backend_refresh_devices:
**/
static gboolean
dkp_backend_refresh_devices (gpointer user_data)
{
DkpBackend *backend;
GPtrArray *array;
DkpDevice *device;
guint i;
backend = DKP_BACKEND (user_data);
array = dkp_device_list_get_array (backend->priv->device_list);
for (i = 0; i < array->len; i++) {
device = DKP_DEVICE (g_ptr_array_index (array, i));
dkp_device_refresh_internal (device);
}
g_ptr_array_unref (array);
return TRUE;
}
/**
* dkp_backend_acpi_devd_notify:
**/
static gboolean
dkp_backend_acpi_devd_notify (DkpBackend *backend, const char *system, const char *subsystem, const char *type, const char *data)
{
GObject *object = NULL;
DkpAcpiNative *native = NULL;
if (strcmp (system, "ACPI"))
return FALSE;
if (!strcmp (subsystem, "ACAD")) {
native = dkp_acpi_native_new ("hw.acpi.acline");
object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
} else if (!strcmp (subsystem, "CMBAT")) {
char *ptr;
int unit;
ptr = strstr (type, ".BAT");
if (ptr != NULL && sscanf (ptr, ".BAT%i", &unit)) {
native = dkp_acpi_native_new_driver_unit ("battery", unit);
object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
if (object == NULL) {
gpointer hptr;
hptr = g_hash_table_lookup (backend->priv->handle_map, type);
if (hptr != NULL) {
object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (hptr));
}
}
}
} else if (!strcmp (subsystem, "Lid")) {
gboolean is_present;
gboolean is_closed;
g_object_get (backend->priv->daemon,
"lid-is-present", &is_present, NULL);
if (!is_present) {
egg_warning ("received lid event without a configured lid; cold-plugging one");
dkp_backend_lid_coldplug (backend);
/* FALLTHROUGH */
}
is_closed = (data != NULL && !strcmp (data, "notify=0x00")) ?
TRUE : FALSE;
g_object_set (backend->priv->daemon, "lid-is-closed", is_closed, NULL);
goto out;
}
if (native == NULL)
goto out;
if (object == NULL) {
egg_warning ("did not find existing %s device; cold-plugging a new one", subsystem);
dkp_backend_create_new_device (backend, native);
goto out;
}
dkp_device_refresh_internal (DKP_DEVICE (object));
if (object != NULL)
g_object_unref (object);
out:
if (native != NULL)
g_object_unref (native);
return TRUE;
}
/**
* dkp_backend_create_new_device:
**/
static gboolean
dkp_backend_create_new_device (DkpBackend *backend, DkpAcpiNative *native)
{
DkpDevice *device;
gboolean ret;
device = DKP_DEVICE (dkp_device_supply_new ());
ret = dkp_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
if (!ret)
g_object_unref (device);
else {
if (!strncmp (dkp_acpi_native_get_path (native), "dev.", strlen ("dev."))) {
const char *path;
path = dkp_acpi_native_get_path (native);
if (dkp_has_sysctl ("%s.%%location", path)) {
char *location;
location = dkp_get_string_sysctl (NULL, "%s.%%location", path);
if (location != NULL && strstr (location, "handle=") != NULL) {
char *handle;
handle = strstr (location, "handle=");
handle += strlen ("handle=");
g_hash_table_insert (backend->priv->handle_map, g_strdup (handle), g_object_ref (native));
}
g_free (location);
}
}
g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, native, device);
}
return ret;
}
/**
* dkp_backend_lid_coldplug:
**/
static void
dkp_backend_lid_coldplug (DkpBackend *backend)
{
char *lid_state;
lid_state = dkp_get_string_sysctl (NULL, "hw.acpi.lid_switch_state");
if (lid_state && strcmp (lid_state, "NONE")) {
g_object_set (backend->priv->daemon, "lid-is-present", TRUE, NULL);
}
g_free (lid_state);
}
/**
* dkp_backend_coldplug:
* @backend: The %DkpBackend class instance
* @daemon: The %DkpDaemon controlling instance
*
* Finds all the devices already plugged in, and emits device-add signals for
* each of them.
*
* Return value: %TRUE for success
**/
gboolean
dkp_backend_coldplug (DkpBackend *backend, DkpDaemon *daemon)
{
DkpAcpiNative *acnative;
int i;
backend->priv->daemon = g_object_ref (daemon);
backend->priv->device_list = dkp_daemon_get_device_list (daemon);
for (i = 0; i < (int) G_N_ELEMENTS (handlers); i++) {
int j;
for (j = 0; dkp_has_sysctl ("dev.%s.%i.%%driver", handlers[i], j); j++) {
DkpAcpiNative *native;
DkpDevice *device;
GObject *object;
native = dkp_acpi_native_new_driver_unit (handlers[i], j);
object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
if (object != NULL) {
device = DKP_DEVICE (object);
egg_warning ("treating add event as change event on %s", dkp_device_get_object_path (device));
dkp_device_refresh_internal (device);
} else {
dkp_backend_create_new_device (backend, native);
}
if (object != NULL) {
g_object_unref (object);
}
if (native != NULL) {
g_object_unref (native);
}
}
}
dkp_backend_lid_coldplug (backend);
acnative = dkp_acpi_native_new ("hw.acpi.acline");
dkp_backend_create_new_device (backend, acnative);
g_object_unref (acnative);
dkp_devd_init (backend);
backend->priv->poll_timer_id =
g_timeout_add_seconds (DKP_BACKEND_REFRESH_TIMEOUT,
(GSourceFunc) dkp_backend_refresh_devices,
backend);
return TRUE;
}
/**
* dkp_backend_get_powersave_command:
**/
gchar *
dkp_backend_get_powersave_command (DkpBackend *backend, gboolean powersave)
{
/* XXX: Do we want to use powerd here? */
return NULL;
}
/**
* dkp_backend_get_suspend_command:
**/
gchar *
dkp_backend_get_suspend_command (DkpBackend *backend)
{
return g_strdup (DKP_BACKEND_SUSPEND_COMMAND);
}
/**
* dkp_backend_get_hibernate_command:
**/
gchar *
dkp_backend_get_hibernate_command (DkpBackend *backend)
{
return g_strdup (DKP_BACKEND_HIBERNATE_COMMAND);
}
/**
* dkp_backend_can_suspend:
**/
gboolean
dkp_backend_can_suspend (DkpBackend *backend)
{
return dkp_backend_supports_sleep_state ("S3");
}
/**
* dkp_backend_can_hibernate:
**/
gboolean
dkp_backend_can_hibernate (DkpBackend *backend)
{
return dkp_backend_supports_sleep_state ("S4");
}
gboolean
dkp_backend_has_encrypted_swap (DkpBackend *backend)
{
/* XXX: Add support for GELI? */
return FALSE;
}
gfloat
dkp_backend_get_used_swap (DkpBackend *backend)
{
gfloat percent;
kvm_t *kd;
char errbuf[_POSIX2_LINE_MAX];
int nswdev;
struct kvm_swap kvmsw[16];
kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf);
if (kd == NULL) {
egg_warning ("failed to open kvm: '%s'", errbuf);
return 0.0f;
}
nswdev = kvm_getswapinfo (kd, kvmsw, 16, 0);
if (nswdev == 0) {
percent = 100.0f;
goto out;
}
if (nswdev < 0) {
egg_warning ("failed to get swap info: '%s'", kvm_geterr (kd));
percent = 0.0f;
goto out;
}
percent = (gfloat) ((gfloat) ((gfloat) kvmsw[nswdev].ksw_used / (gfloat) kvmsw[nswdev].ksw_total) * 100.0f);
out:
kvm_close (kd);
return percent;
}
/**
* dkp_backend_supports_sleep_state:
**/
static gboolean
dkp_backend_supports_sleep_state (const char *state)
{
char *sleep_states;
gboolean ret = FALSE;
sleep_states = dkp_get_string_sysctl (NULL, "hw.acpi.supported_sleep_state");
if (sleep_states != NULL) {
if (strstr (sleep_states, state) != NULL)
ret = TRUE;
}
g_free (sleep_states);
return ret;
}
/**
* dkp_backend_class_init:
* @klass: The DkpBackendClass
**/
static void
dkp_backend_class_init (DkpBackendClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = dkp_backend_finalize;
signals [SIGNAL_DEVICE_ADDED] =
g_signal_new ("device-added",
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (DkpBackendClass, device_added),
NULL, NULL, dkp_marshal_VOID__POINTER_POINTER,
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
signals [SIGNAL_DEVICE_REMOVED] =
g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (DkpBackendClass, device_removed),
NULL, NULL, dkp_marshal_VOID__POINTER_POINTER,
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
g_type_class_add_private (klass, sizeof (DkpBackendPrivate));
}
/**
* dkp_backend_init:
**/
static void
dkp_backend_init (DkpBackend *backend)
{
backend->priv = DKP_BACKEND_GET_PRIVATE (backend);
backend->priv->daemon = NULL;
backend->priv->device_list = NULL;
backend->priv->handle_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
backend->priv->poll_timer_id = 0;
}
/**
* dkp_backend_finalize:
**/
static void
dkp_backend_finalize (GObject *object)
{
DkpBackend *backend;
g_return_if_fail (DKP_IS_BACKEND (object));
backend = DKP_BACKEND (object);
if (backend->priv->daemon != NULL)
g_object_unref (backend->priv->daemon);
if (backend->priv->device_list != NULL)
g_object_unref (backend->priv->device_list);
if (backend->priv->handle_map != NULL)
g_hash_table_unref (backend->priv->handle_map);
if (backend->priv->poll_timer_id > 0)
g_source_remove (backend->priv->poll_timer_id);
G_OBJECT_CLASS (dkp_backend_parent_class)->finalize (object);
}
/**
* dkp_backend_new:
*
* Return value: a new %DkpBackend object.
**/
DkpBackend *
dkp_backend_new (void)
{
DkpBackend *backend;
backend = g_object_new (DKP_TYPE_BACKEND, NULL);
return DKP_BACKEND (backend);
}
/***************************************************************************
*** MAKE CHECK TESTS ***
***************************************************************************/
#ifdef EGG_TEST
#include "egg-test.h"
void
dkp_backend_test (gpointer user_data)
{
EggTest *test = (EggTest *) user_data;
DkpBackend *backend;
if (!egg_test_start (test, "DkpBackend"))
return;
/************************************************************/
egg_test_title (test, "get instance");
backend = dkp_backend_new ();
egg_test_assert (test, backend != NULL);
/* unref */
g_object_unref (backend);
egg_test_end (test);
}
#endif

245
src/freebsd/dkp-devd.c Normal file
View file

@ -0,0 +1,245 @@
/***************************************************************************
* CVSID: $Id$
*
* dkp-devd.c : process devd events
*
* Copyright (C) 2006, 2007 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "egg-debug.h"
#include "dkp-backend.h"
#include "dkp-backend-acpi.h"
#include "dkp-devd.h"
#define DKP_DEVD_SOCK_PATH "/var/run/devd.pipe"
#define DKP_DEVD_EVENT_NOTIFY '!'
#define DKP_DEVD_EVENT_ADD '+'
#define DKP_DEVD_EVENT_REMOVE '-'
#define DKP_DEVD_EVENT_NOMATCH '?'
static DkpDevdHandler *handlers[] = {
&dkp_backend_acpi_devd_handler,
};
static gboolean dkp_devd_inited = FALSE;
#if 0
static GHashTable *
dkp_devd_parse_params (const char *str)
{
GHashTable *params;
char **pairs;
int i;
g_return_val_if_fail(str != NULL, FALSE);
params = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
pairs = g_strsplit(str, " ", 0);
for (i = 0; pairs[i]; i++) {
char *equal;
equal = strchr(pairs[i], '=');
g_hash_table_insert(params,
equal ? g_strndup(pairs[i], equal - pairs[i]) : g_strdup(pairs[i]),
equal ? g_strdup(equal + 1) : NULL);
}
g_strfreev(pairs);
return params;
}
#endif
static gboolean
dkp_devd_parse_notify (const char *event,
char **system,
char **subsystem,
char **type,
char **data)
{
char **items;
gboolean status = FALSE;
/*
!system=IFNET subsystem=bge0 type=LINK_DOWN
*/
g_return_val_if_fail(event != NULL, FALSE);
g_return_val_if_fail(system != NULL, FALSE);
g_return_val_if_fail(subsystem != NULL, FALSE);
g_return_val_if_fail(type != NULL, FALSE);
g_return_val_if_fail(data != NULL, FALSE);
items = g_strsplit(event, " ", 0);
if (g_strv_length(items) < 3)
goto end;
if (! g_str_has_prefix(items[0], "system=") ||
! g_str_has_prefix(items[1], "subsystem=") ||
! g_str_has_prefix(items[2], "type="))
goto end;
*system = g_strdup(items[0] + 7);
*subsystem = g_strdup(items[1] + 10);
*type = g_strdup(items[2] + 5);
*data = g_strdup(items[3]); /* may be NULL */
status = TRUE;
end:
g_strfreev(items);
return status;
}
static void
dkp_devd_process_notify_event (DkpBackend *backend,
const char *system,
const char *subsystem,
const char *type,
const char *data)
{
int i;
g_return_if_fail(backend != NULL);
g_return_if_fail(system != NULL);
g_return_if_fail(subsystem != NULL);
g_return_if_fail(type != NULL);
g_return_if_fail(data != NULL);
for (i = 0; i < (int) G_N_ELEMENTS(handlers); i++)
if (handlers[i]->notify && handlers[i]->notify(backend, system, subsystem, type, data))
return;
/* no default action */
}
static void
dkp_devd_process_event (const char *event, gpointer user_data)
{
DkpBackend *backend;
g_return_if_fail(event != NULL);
backend = DKP_BACKEND(user_data);
egg_debug("received devd event: '%s'", event);
switch (event[0]) {
case DKP_DEVD_EVENT_ADD:
case DKP_DEVD_EVENT_REMOVE:
/* Do nothing as we don't currently hotplug ACPI devices. */
return;
case DKP_DEVD_EVENT_NOTIFY: {
char *system;
char *subsystem;
char *type;
char *data;
if (! dkp_devd_parse_notify(event + 1, &system, &subsystem, &type, &data))
goto malformed;
dkp_devd_process_notify_event(backend, system, subsystem, type, data);
g_free(system);
g_free(subsystem);
g_free(type);
g_free(data);
}
return;
case DKP_DEVD_EVENT_NOMATCH:
/* Do nothing. */
return;
}
malformed:
egg_warning("malformed devd event: %s", event);
}
static gboolean
dkp_devd_event_cb (GIOChannel *source, GIOCondition condition,
gpointer user_data)
{
char *event;
gsize terminator;
GIOStatus status;
status = g_io_channel_read_line(source, &event, NULL, &terminator, NULL);
if (status == G_IO_STATUS_NORMAL) {
event[terminator] = 0;
dkp_devd_process_event(event, user_data);
g_free(event);
} else if (status == G_IO_STATUS_AGAIN) {
dkp_devd_init(DKP_BACKEND(user_data));
if (dkp_devd_inited) {
int fd;
fd = g_io_channel_unix_get_fd(source);
g_io_channel_shutdown(source, FALSE, NULL);
close(fd);
return FALSE;
}
}
return TRUE;
}
void
dkp_devd_init (DkpBackend *backend)
{
int event_fd;
struct sockaddr_un addr;
event_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (event_fd < 0) {
egg_warning("failed to create event socket: '%s'", g_strerror(errno));
dkp_devd_inited = FALSE;
return;
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, DKP_DEVD_SOCK_PATH, sizeof(addr.sun_path));
if (connect(event_fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
GIOChannel *channel;
channel = g_io_channel_unix_new(event_fd);
g_io_add_watch(channel, G_IO_IN, dkp_devd_event_cb, backend);
g_io_channel_unref(channel);
dkp_devd_inited = TRUE;
} else {
egg_warning("failed to connect to %s: '%s'", DKP_DEVD_SOCK_PATH,
g_strerror(errno));
close(event_fd);
dkp_devd_inited = FALSE;
}
}

46
src/freebsd/dkp-devd.h Normal file
View file

@ -0,0 +1,46 @@
/***************************************************************************
* CVSID: $Id$
*
* dkp-devd.h : process devd events
*
* Copyright (C) 2006, 2009 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifndef _DKP_DEVD_H
#define _DKP_DEVD_H
#include "config.h"
#include "dkp-backend.h"
#include <glib.h>
typedef struct
{
/* return TRUE to consume the event and stop processing */
gboolean (*notify) (DkpBackend *backend,
const char *system,
const char *subsystem,
const char *type,
const char *data); /* may be NULL */
} DkpDevdHandler;
void dkp_devd_init (DkpBackend *backend);
#endif /* _DKP_DEVD_H */

View file

@ -0,0 +1,544 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "config.h"
#include <string.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <dev/acpica/acpiio.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gprintf.h>
#include <glib/gi18n-lib.h>
#include <glib-object.h>
#include "dkp-acpi-native.h"
#include "dkp-util.h"
#include "egg-debug.h"
#include "dkp-enum.h"
#include "dkp-device-supply.h"
#define DKP_ACPIDEV "/dev/acpi"
G_DEFINE_TYPE (DkpDeviceSupply, dkp_device_supply, DKP_TYPE_DEVICE)
static gboolean dkp_device_supply_refresh (DkpDevice *device);
static DkpDeviceTechnology dkp_device_supply_convert_device_technology (const char *type);
static gboolean dkp_device_supply_acline_coldplug (DkpDevice *device);
static gboolean dkp_device_supply_battery_coldplug (DkpDevice *device, DkpAcpiNative *native);
static gboolean dkp_device_supply_acline_set_properties (DkpDevice *device);
static gboolean dkp_device_supply_battery_set_properties (DkpDevice *device, DkpAcpiNative *native);
static gboolean dkp_device_supply_get_on_battery (DkpDevice *device, gboolean *on_battery);
static gboolean dkp_device_supply_get_low_battery (DkpDevice *device, gboolean *low_battery);
static gboolean dkp_device_supply_get_online (DkpDevice *device, gboolean *online);
/**
* dkp_device_supply_convert_device_technology:
*
* This is taken from linux/dkp-device-supply.c.
**/
static DkpDeviceTechnology
dkp_device_supply_convert_device_technology (const char *type)
{
if (type == NULL)
return DKP_DEVICE_TECHNOLOGY_UNKNOWN;
if (g_ascii_strcasecmp (type, "li-ion") == 0 ||
g_ascii_strcasecmp (type, "lion") == 0)
return DKP_DEVICE_TECHNOLOGY_LITHIUM_ION;
if (g_ascii_strcasecmp (type, "pb") == 0 ||
g_ascii_strcasecmp (type, "pbac") == 0)
return DKP_DEVICE_TECHNOLOGY_LEAD_ACID;
if (g_ascii_strcasecmp (type, "lip") == 0 ||
g_ascii_strcasecmp (type, "lipo") == 0 ||
g_ascii_strcasecmp (type, "li-poly") == 0)
return DKP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER;
if (g_ascii_strcasecmp (type, "nimh") == 0)
return DKP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE;
if (g_ascii_strcasecmp (type, "lifo") == 0)
return DKP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE;
return DKP_DEVICE_TECHNOLOGY_UNKNOWN;
}
/**
* dkp_device_supply_reset_values:
**/
static void
dkp_device_supply_reset_values (DkpDevice *device)
{
/* reset to default */
g_object_set (device,
"vendor", NULL,
"model", NULL,
"serial", NULL,
"update-time", (guint64) 0,
"power-supply", FALSE,
"online", FALSE,
"energy", (gdouble) 0.0,
"is-present", FALSE,
"is-rechargeable", FALSE,
"has-history", FALSE,
"has-statistics", FALSE,
"state", DKP_DEVICE_STATE_UNKNOWN,
"capacity", (gdouble) 0.0,
"energy-empty", (gdouble) 0.0,
"energy-full", (gdouble) 0.0,
"energy-full-design", (gdouble) 0.0,
"energy-rate", (gdouble) 0.0,
"voltage", (gdouble) 0.0,
"time-to-empty", (guint64) 0,
"time-to-full", (guint64) 0,
"percentage", (gdouble) 0.0,
"technology", DKP_DEVICE_TECHNOLOGY_UNKNOWN,
NULL);
}
/**
* dkp_device_supply_acline_coldplug:
**/
static gboolean
dkp_device_supply_acline_coldplug (DkpDevice *device)
{
gboolean ret;
g_object_set (device,
"online", FALSE,
"power-supply", TRUE,
"type", DKP_DEVICE_TYPE_LINE_POWER,
NULL);
ret = dkp_device_supply_acline_set_properties (device);
return ret;
}
/**
* dkp_device_supply_battery_coldplug:
**/
static gboolean
dkp_device_supply_battery_coldplug (DkpDevice *device, DkpAcpiNative *native)
{
gboolean ret;
g_object_set (device, "type", DKP_DEVICE_TYPE_BATTERY, NULL);
ret = dkp_device_supply_battery_set_properties (device, native);
return ret;
}
/**
* dkp_device_supply_battery_set_properties:
**/
static gboolean
dkp_device_supply_battery_set_properties (DkpDevice *device, DkpAcpiNative *native)
{
int fd;
gdouble volt, dvolt, rate, lastfull, cap, dcap, lcap, capacity;
gboolean is_present;
gboolean ret = FALSE;
guint64 time_to_empty, time_to_full;
char *vendor, *model, *serial;
DkpDeviceTechnology technology;
DkpDeviceState state;
union acpi_battery_ioctl_arg battif, battst, battinfo;
if (!dkp_has_sysctl ("hw.acpi.battery.units"))
return FALSE;
battif.unit = battst.unit = battinfo.unit =
dkp_acpi_native_get_unit (native);
fd = open (DKP_ACPIDEV, O_RDONLY);
if (fd < 0) {
egg_warning ("unable to open %s: '%s'", DKP_ACPIDEV, g_strerror (errno));
return FALSE;
}
if (ioctl (fd, ACPIIO_BATT_GET_BIF, &battif) == -1) {
egg_warning ("ioctl ACPIIO_BATT_GET_BIF failed for battery %d: '%s'", battif.unit, g_strerror (errno));
goto end;
}
if (ioctl (fd, ACPIIO_BATT_GET_BST, &battst) == -1) {
egg_warning ("ioctl ACPIIO_BATT_GET_BST failed for battery %d: '%s'", battst.unit, g_strerror (errno));
goto end;
}
if (ioctl (fd, ACPIIO_BATT_GET_BATTINFO, &battinfo) == -1) {
egg_warning ("ioctl ACPIIO_BATT_GET_BATTINFO failed for battery %d: '%s'", battinfo.unit, g_strerror (errno));
goto end;
}
ret = TRUE;
is_present = (battst.bst.state == ACPI_BATT_STAT_NOT_PRESENT) ? FALSE : TRUE;
g_object_set (device, "is-present", is_present, NULL);
if (!is_present) {
dkp_device_supply_reset_values (device);
goto end;
}
vendor = dkp_make_safe_string (battif.bif.oeminfo);
model = dkp_make_safe_string (battif.bif.model);
serial = dkp_make_safe_string (battif.bif.serial);
technology = dkp_device_supply_convert_device_technology (battif.bif.type);
g_object_set (device,
"vendor", vendor,
"model", model,
"serial", serial,
"power-supply", TRUE,
"technology", technology,
"has-history", TRUE,
"has-statistics", TRUE,
NULL);
g_free (vendor);
g_free (model);
g_free (serial);
g_object_set (device, "is-rechargeable",
battif.bif.btech == 0 ? FALSE : TRUE, NULL);
volt = (gdouble) battst.bst.volt;
dvolt = (gdouble) battif.bif.dvol;
lastfull = (gdouble) battif.bif.lfcap;
dcap = (gdouble) battif.bif.dcap;
rate = (gdouble) battst.bst.rate;
cap = (gdouble) battst.bst.cap;
lcap = (gdouble) battif.bif.lcap;
if (rate == 0xffff)
rate = 0.0f;
if (rate > 100.0f * 1000.0f)
rate = 0.0f;
dvolt /= 1000.0f;
volt /= 1000.0f;
if (battif.bif.units == ACPI_BIF_UNITS_MA) {
if (dvolt <= 0.0f)
dvolt = 1.0f;
if (volt <= 0.0f || volt > dvolt)
volt = dvolt;
dcap *= volt;
lastfull *= volt;
rate *= volt;
cap *= volt;
lcap *= volt;
}
dcap /= 1000.0f;
lastfull /= 1000.0f;
rate /= 1000.0f;
cap /= 1000.0f;
lcap /= 1000.0f;
if (cap == 0.0f)
rate = 0.0f;
capacity = 0.0f;
if (lastfull > 0 && dcap > 0) {
capacity = (lastfull / dcap) * 100.0f;
if (capacity < 0)
capacity = 0.0f;
if (capacity > 100.0)
capacity = 100.0f;
}
g_object_set (device,
"percentage", (gdouble) battinfo.battinfo.cap,
"energy", cap,
"energy-full", lastfull,
"energy-full-design", dcap,
"energy-rate", rate,
"energy-empty", lcap,
"voltage", volt,
"capacity", capacity,
NULL);
time_to_empty = 0;
time_to_full = 0;
if (battinfo.battinfo.state & ACPI_BATT_STAT_DISCHARG) {
state = DKP_DEVICE_STATE_DISCHARGING;
if (battinfo.battinfo.min > 0)
time_to_empty = battinfo.battinfo.min * 60;
else if (rate > 0) {
time_to_empty = 3600 * (cap / rate);
if (time_to_empty > (20 * 60 * 60))
time_to_empty = 0;
}
} else if (battinfo.battinfo.state & ACPI_BATT_STAT_CHARGING) {
state = DKP_DEVICE_STATE_CHARGING;
if (battinfo.battinfo.min > 0)
time_to_full = battinfo.battinfo.min * 60;
else if (rate > 0) {
time_to_full = 3600 * ((lastfull - cap) / rate);
if (time_to_full > (20 * 60 * 60))
time_to_full = 0;
}
} else if (battinfo.battinfo.state & ACPI_BATT_STAT_CRITICAL) {
state = DKP_DEVICE_STATE_EMPTY;
} else if (battinfo.battinfo.state == 0) {
state = DKP_DEVICE_STATE_FULLY_CHARGED;
} else {
state = DKP_DEVICE_STATE_UNKNOWN;
}
g_object_set (device,
"state", state,
"time-to-empty", time_to_empty,
"time-to-full", time_to_full,
NULL);
end:
close (fd);
return ret;
}
/**
* dkp_device_supply_acline_set_properties:
**/
static gboolean
dkp_device_supply_acline_set_properties (DkpDevice *device)
{
int acstate;
if (dkp_get_int_sysctl (&acstate, NULL, "hw.acpi.acline")) {
g_object_set (device, "online", acstate ? TRUE : FALSE, NULL);
return TRUE;
}
return FALSE;
}
/**
* dkp_device_supply_coldplug:
* Return %TRUE on success, %FALSE if we failed to get data and should be removed
**/
static gboolean
dkp_device_supply_coldplug (DkpDevice *device)
{
DkpAcpiNative *native;
const gchar *native_path;
const gchar *driver;
gboolean ret = FALSE;
dkp_device_supply_reset_values (device);
native = DKP_ACPI_NATIVE (dkp_device_get_native (device));
native_path = dkp_acpi_native_get_path (native);
driver = dkp_acpi_native_get_driver (native);
if (native_path == NULL) {
egg_warning ("could not get native path for %p", device);
goto out;
}
if (!strcmp (native_path, "hw.acpi.acline")) {
ret = dkp_device_supply_acline_coldplug (device);
goto out;
}
if (!g_strcmp0 (driver, "battery")) {
ret = dkp_device_supply_battery_coldplug (device, native);
goto out;
}
egg_warning ("invalid device %s with driver %s", native_path, driver);
out:
return ret;
}
/**
* dkp_device_supply_refresh:
*
* Return %TRUE on success, %FALSE if we failed to refresh or no data
**/
static gboolean
dkp_device_supply_refresh (DkpDevice *device)
{
GObject *object;
GTimeVal timeval;
DkpDeviceType type;
gboolean ret;
g_object_get (device, "type", &type, NULL);
switch (type) {
case DKP_DEVICE_TYPE_LINE_POWER:
ret = dkp_device_supply_acline_set_properties (device);
break;
case DKP_DEVICE_TYPE_BATTERY:
object = dkp_device_get_native (device);
ret = dkp_device_supply_battery_set_properties (device, DKP_ACPI_NATIVE (object));
break;
default:
g_assert_not_reached ();
break;
}
if (ret) {
g_get_current_time (&timeval);
g_object_set (device, "update-time", (guint64) timeval.tv_sec, NULL);
}
return ret;
}
/**
* dkp_device_supply_get_on_battery:
**/
static gboolean
dkp_device_supply_get_on_battery (DkpDevice *device, gboolean *on_battery)
{
DkpDeviceType type;
DkpDeviceState state;
gboolean is_present;
g_return_val_if_fail (on_battery != NULL, FALSE);
g_object_get (device,
"type", &type,
"state", &state,
"is-present", &is_present,
NULL);
if (type != DKP_DEVICE_TYPE_BATTERY)
return FALSE;
if (state == DKP_DEVICE_STATE_UNKNOWN)
return FALSE;
if (!is_present)
return FALSE;
*on_battery = (state == DKP_DEVICE_STATE_DISCHARGING);
return TRUE;
}
/**
* dkp_device_supply_get_low_battery:
**/
static gboolean
dkp_device_supply_get_low_battery (DkpDevice *device, gboolean *low_battery)
{
gboolean ret;
gboolean on_battery;
gdouble percentage;
g_return_val_if_fail (low_battery != NULL, FALSE);
ret = dkp_device_supply_get_on_battery (device, &on_battery);
if (!ret)
return FALSE;
if (!on_battery) {
*low_battery = FALSE;
return TRUE;
}
g_object_get (device, "percentage", &percentage, NULL);
*low_battery = (percentage < 10.0f);
return TRUE;
}
/**
* dkp_device_supply_get_online:
**/
static gboolean
dkp_device_supply_get_online (DkpDevice *device, gboolean *online)
{
DkpDeviceType type;
gboolean online_tmp;
g_return_val_if_fail (online != NULL, FALSE);
g_object_get (device,
"type", &type,
"online", &online_tmp,
NULL);
if (type != DKP_DEVICE_TYPE_LINE_POWER)
return FALSE;
*online = online_tmp;
return TRUE;
}
/**
* dkp_device_supply_init:
**/
static void
dkp_device_supply_init (DkpDeviceSupply *supply)
{
}
/**
* dkp_device_supply_finalize:
**/
static void
dkp_device_supply_finalize (GObject *object)
{
DkpDeviceSupply *supply;
g_return_if_fail (object != NULL);
g_return_if_fail (DKP_IS_SUPPLY (object));
supply = DKP_DEVICE_SUPPLY (object);
G_OBJECT_CLASS (dkp_device_supply_parent_class)->finalize (object);
}
/**
* dkp_device_supply_class_init:
**/
static void
dkp_device_supply_class_init (DkpDeviceSupplyClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
DkpDeviceClass *device_class = DKP_DEVICE_CLASS (klass);
object_class->finalize = dkp_device_supply_finalize;
device_class->get_on_battery = dkp_device_supply_get_on_battery;
device_class->get_low_battery = dkp_device_supply_get_low_battery;
device_class->get_online = dkp_device_supply_get_online;
device_class->coldplug = dkp_device_supply_coldplug;
device_class->refresh = dkp_device_supply_refresh;
}
/**
* dkp_device_supply_new:
**/
DkpDeviceSupply *
dkp_device_supply_new (void)
{
return g_object_new (DKP_TYPE_SUPPLY, NULL);
}

View file

@ -0,0 +1,56 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
* Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __DKP_DEVICE_SUPPLY_H__
#define __DKP_DEVICE_SUPPLY_H__
#include <glib-object.h>
#include "dkp-device.h"
G_BEGIN_DECLS
#define DKP_TYPE_SUPPLY (dkp_device_supply_get_type ())
#define DKP_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DKP_TYPE_SUPPLY, DkpDeviceSupply))
#define DKP_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DKP_TYPE_SUPPLY, DkpDeviceSupplyClass))
#define DKP_IS_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DKP_TYPE_SUPPLY))
#define DKP_IS_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DKP_TYPE_SUPPLY))
#define DKP_DEVICE_SUPPLY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DKP_TYPE_SUPPLY, DkpDeviceSupplyClass))
typedef struct DkpDeviceSupplyPrivate DkpDeviceSupplyPrivate;
typedef struct
{
DkpDevice parent;
DkpDeviceSupplyPrivate *priv;
} DkpDeviceSupply;
typedef struct
{
DkpDeviceClass parent_class;
} DkpDeviceSupplyClass;
GType dkp_device_supply_get_type (void);
DkpDeviceSupply *dkp_device_supply_new (void);
G_END_DECLS
#endif /* __DKP_DEVICE_SUPPLY_H__ */

66
src/freebsd/dkp-native.c Normal file
View file

@ -0,0 +1,66 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <glib.h>
#include "dkp-acpi-native.h"
#include "dkp-native.h"
/**
* dkp_native_get_native_path:
* @object: the native tracking object
*
* This converts a GObject used as the device data into a native path.
*
* Return value: The native path for the device which is unique, e.g. "/sys/class/power/BAT1"
**/
const gchar *
dkp_native_get_native_path (GObject *object)
{
return dkp_acpi_native_get_path (DKP_ACPI_NATIVE (object));
}
/***************************************************************************
*** MAKE CHECK TESTS ***
***************************************************************************/
#ifdef EGG_TEST
#include "egg-test.h"
void
dkp_native_test (gpointer user_data)
{
EggTest *test = (EggTest *) user_data;
DkpAcpiNative *dan;
const gchar *path;
if (!egg_test_start (test, "DkpNative"))
return;
/************************************************************/
egg_test_title (test, "get instance");
dan = dkp_acpi_native_new_driver_unit ("battery", 0);
path = dkp_native_get_native_path (dan);
egg_test_assert (test, (g_strcmp0 (path, "dev.battery.0") == 0));
g_object_unref (dan);
egg_test_end (test);
}
#endif

145
src/freebsd/dkp-util.c Normal file
View file

@ -0,0 +1,145 @@
/***************************************************************************
* CVSID: $Id$
*
* dkp-util.c : utilities
*
* Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <glib.h>
#include "egg-debug.h"
#include "dkp-util.h"
gboolean
dkp_has_sysctl (const char *format, ...)
{
va_list args;
char *name;
size_t value_len;
gboolean status;
g_return_val_if_fail(format != NULL, FALSE);
va_start(args, format);
name = g_strdup_vprintf(format, args);
va_end(args);
status = sysctlbyname(name, NULL, &value_len, NULL, 0) == 0;
g_free(name);
return status;
}
gboolean
dkp_get_int_sysctl (int *value, GError **err, const char *format, ...)
{
va_list args;
char *name;
size_t value_len = sizeof(int);
gboolean status;
g_return_val_if_fail(value != NULL, FALSE);
g_return_val_if_fail(format != NULL, FALSE);
va_start(args, format);
name = g_strdup_vprintf(format, args);
va_end(args);
status = sysctlbyname(name, value, &value_len, NULL, 0) == 0;
if (! status)
g_set_error(err, 0, 0, "%s", g_strerror(errno));
g_free(name);
return status;
}
char *
dkp_get_string_sysctl (GError **err, const char *format, ...)
{
va_list args;
char *name;
size_t value_len;
char *str = NULL;
g_return_val_if_fail(format != NULL, FALSE);
va_start(args, format);
name = g_strdup_vprintf(format, args);
va_end(args);
if (sysctlbyname(name, NULL, &value_len, NULL, 0) == 0) {
str = g_new(char, value_len + 1);
if (sysctlbyname(name, str, &value_len, NULL, 0) == 0)
str[value_len] = 0;
else {
g_free(str);
str = NULL;
}
}
if (! str)
g_set_error(err, 0, 0, "%s", g_strerror(errno));
g_free(name);
return str;
}
/**
* dkp_util_make_safe_string:
*
* This is adapted from linux/dkp-device-supply.c.
**/
char *
dkp_make_safe_string (const char *text)
{
guint i;
guint idx = 0;
char *ret;
/* no point in checking */
if (text == NULL)
return NULL;
ret = g_strdup (text);
/* shunt up only safe chars */
for (i = 0; ret[i] != '\0'; i++) {
if (g_ascii_isprint (ret[i])) {
/* only copy if the address is going to change */
if (idx != i)
ret[idx] = ret[i];
idx++;
} else {
egg_debug ("invalid char '%c'", ret[i]);
}
}
/* ensure null terminated */
ret[idx] = '\0';
return ret;
}

50
src/freebsd/dkp-util.h Normal file
View file

@ -0,0 +1,50 @@
/***************************************************************************
* CVSID: $Id$
*
* dkp-util.h : utilities
*
* Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifndef _DKP_UTIL_H
#define _DKP_UTIL_H
#include "config.h"
#include <stdarg.h>
#include <glib.h>
#define DKP_BOOL_TO_STRING(val) ((val) ? "true" : "false")
#define DKP_LIST_FOREACH(var, head) \
for ((var) = (head); \
(var); \
(var) = (var)->next)
gboolean dkp_has_sysctl (const char *format, ...) G_GNUC_PRINTF(1, 2);
gboolean dkp_get_int_sysctl (int *value,
GError **err,
const char *format,
...) G_GNUC_PRINTF(3, 4);
char *dkp_get_string_sysctl (GError **err,
const char *format,
...) G_GNUC_PRINTF(2, 3);
char *dkp_make_safe_string (const char *text);
#endif /* _DKP_UTIL_H */