diff options
author | Joe Marcus Clarke <marcus@FreeBSD.org> | 2010-01-02 14:03:05 -0500 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2010-01-03 08:54:30 +0000 |
commit | 131bc12a81855a30cc300dff237ac78f803e595f (patch) | |
tree | 2b5a1536f64f845c18e5cf78903874060f14c059 /src/freebsd | |
parent | 725acd4d354c27eb5828e8d6e388ecf34a7c6303 (diff) | |
download | upower-131bc12a81855a30cc300dff237ac78f803e595f.tar.gz |
import the FreeBSD backend
Add a backend for FreeBSD supporting AC power lines, batteries, and
lid state.
Diffstat (limited to 'src/freebsd')
-rw-r--r-- | src/freebsd/Makefile.am | 45 | ||||
-rw-r--r-- | src/freebsd/TODO | 4 | ||||
-rw-r--r-- | src/freebsd/dkp-acpi-native.c | 234 | ||||
-rw-r--r-- | src/freebsd/dkp-acpi-native.h | 48 | ||||
-rw-r--r-- | src/freebsd/dkp-acpi-native.vala | 46 | ||||
-rw-r--r-- | src/freebsd/dkp-backend-acpi.h | 33 | ||||
-rw-r--r-- | src/freebsd/dkp-backend.c | 511 | ||||
-rw-r--r-- | src/freebsd/dkp-devd.c | 245 | ||||
-rw-r--r-- | src/freebsd/dkp-devd.h | 46 | ||||
-rw-r--r-- | src/freebsd/dkp-device-supply.c | 544 | ||||
-rw-r--r-- | src/freebsd/dkp-device-supply.h | 56 | ||||
-rw-r--r-- | src/freebsd/dkp-native.c | 66 | ||||
-rw-r--r-- | src/freebsd/dkp-util.c | 145 | ||||
-rw-r--r-- | src/freebsd/dkp-util.h | 50 |
14 files changed, 2073 insertions, 0 deletions
diff --git a/src/freebsd/Makefile.am b/src/freebsd/Makefile.am new file mode 100644 index 0000000..32016bb --- /dev/null +++ b/src/freebsd/Makefile.am @@ -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 *~ + diff --git a/src/freebsd/TODO b/src/freebsd/TODO new file mode 100644 index 0000000..4e1b72b --- /dev/null +++ b/src/freebsd/TODO @@ -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. diff --git a/src/freebsd/dkp-acpi-native.c b/src/freebsd/dkp-acpi-native.c new file mode 100644 index 0000000..71ff1b2 --- /dev/null +++ b/src/freebsd/dkp-acpi-native.c @@ -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; + } +} + + + + diff --git a/src/freebsd/dkp-acpi-native.h b/src/freebsd/dkp-acpi-native.h new file mode 100644 index 0000000..987e330 --- /dev/null +++ b/src/freebsd/dkp-acpi-native.h @@ -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 diff --git a/src/freebsd/dkp-acpi-native.vala b/src/freebsd/dkp-acpi-native.vala new file mode 100644 index 0000000..7710798 --- /dev/null +++ b/src/freebsd/dkp-acpi-native.vala @@ -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); + } +} diff --git a/src/freebsd/dkp-backend-acpi.h b/src/freebsd/dkp-backend-acpi.h new file mode 100644 index 0000000..d351f81 --- /dev/null +++ b/src/freebsd/dkp-backend-acpi.h @@ -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 */ diff --git a/src/freebsd/dkp-backend.c b/src/freebsd/dkp-backend.c new file mode 100644 index 0000000..55f0c32 --- /dev/null +++ b/src/freebsd/dkp-backend.c @@ -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 + diff --git a/src/freebsd/dkp-devd.c b/src/freebsd/dkp-devd.c new file mode 100644 index 0000000..352a1b9 --- /dev/null +++ b/src/freebsd/dkp-devd.c @@ -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; + } +} diff --git a/src/freebsd/dkp-devd.h b/src/freebsd/dkp-devd.h new file mode 100644 index 0000000..b5e86ee --- /dev/null +++ b/src/freebsd/dkp-devd.h @@ -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 */ diff --git a/src/freebsd/dkp-device-supply.c b/src/freebsd/dkp-device-supply.c new file mode 100644 index 0000000..01f5be8 --- /dev/null +++ b/src/freebsd/dkp-device-supply.c @@ -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); +} + diff --git a/src/freebsd/dkp-device-supply.h b/src/freebsd/dkp-device-supply.h new file mode 100644 index 0000000..b767eac --- /dev/null +++ b/src/freebsd/dkp-device-supply.h @@ -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__ */ + diff --git a/src/freebsd/dkp-native.c b/src/freebsd/dkp-native.c new file mode 100644 index 0000000..944111a --- /dev/null +++ b/src/freebsd/dkp-native.c @@ -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 + diff --git a/src/freebsd/dkp-util.c b/src/freebsd/dkp-util.c new file mode 100644 index 0000000..104eb0b --- /dev/null +++ b/src/freebsd/dkp-util.c @@ -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; +} diff --git a/src/freebsd/dkp-util.h b/src/freebsd/dkp-util.h new file mode 100644 index 0000000..ff4fe24 --- /dev/null +++ b/src/freebsd/dkp-util.h @@ -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 */ |