hal/hald/linux2 apm.c,NONE,1.1 apm.h,NONE,1.1

David Zeuthen david at freedesktop.org
Wed Feb 2 16:24:44 PST 2005


Update of /cvs/hal/hal/hald/linux2
In directory gabe:/tmp/cvs-serv15682/hald/linux2

Added Files:
	apm.c apm.h 
Log Message:
Forgot to add files

--- NEW FILE: apm.c ---
/***************************************************************************
 * CVSID: $Id: apm.c,v 1.1 2005/02/03 00:24:42 david Exp $
 *
 * Copyright (C) 2005 Richard Hughes <richard at hughsie.com>
 * Copyright (C) 2005 David Zeuthen, Red Hat Inc., <davidz at redhat.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <string.h>

#include "../callout.h"
#include "../device_info.h"
#include "../logger.h"
#include "../hald_dbus.h"
#include "util.h"

#include "apm.h"
#include "hotplug.h"

enum {
	APM_TYPE_BATTERY,
	APM_TYPE_AC_ADAPTER
};


typedef struct APMDevHandler_s
{
	int apm_type;
	HalDevice *(*add) (const gchar *apm_path, HalDevice *parent, struct APMDevHandler_s *handler);
	gboolean (*compute_udi) (HalDevice *d, struct APMDevHandler_s *handler);
	gboolean (*remove) (HalDevice *d, struct APMDevHandler_s *handler);
	gboolean (*refresh) (HalDevice *d, struct APMDevHandler_s *handler);
} APMDevHandler;

typedef struct {
	char driver_version[256];
	int version_major;
	int version_minor;
	int flags;
	int ac_line_status;
	int battery_status;
	int battery_flags;
	int battery_percentage;
	int battery_time;
	int using_minutes;
} APMInfo;

static gboolean 
read_from_apm (const char *apm_file, APMInfo *i)
{
	char *buf;
	gboolean ret;

	ret = FALSE;

	if ((buf = hal_util_get_string_from_file ("", apm_file)) == NULL)
		goto out;

	if (sscanf (buf, "%s %d.%d %x %x %x %x %d%% %d",
		    &i->driver_version,
		    &i->version_major,
		    &i->version_minor,
		    &i->flags,
		    &i->ac_line_status,
		    &i->battery_status,
		    &i->battery_flags,
		    &i->battery_percentage,
		    &i->battery_time) != 9)
		goto out;

	ret = TRUE;

out:
	return ret;
}

enum
{
	BATTERY_HIGH     = 0,
	BATTERY_LOW      = 1,
	BATTERY_CRITICAL = 2,
	BATTERY_CHARGING = 3
};

static gboolean
battery_refresh (HalDevice *d, APMDevHandler *handler)
{
	const char *path;
	APMInfo i;

	path = hal_device_property_get_string (d, "linux.apm_path");
	if (path == NULL)
		return FALSE;

	hal_device_property_set_string (d, "info.product", "Battery Bay");
	hal_device_property_set_string (d, "battery.type", "primary");
	hal_device_property_set_string (d, "info.category", "battery");
	hal_device_add_capability (d, "battery");

	/* typical : 1.16ac 1.2 0x02 0x01 0x03 0x09 98% 88 min */

	read_from_apm (path, &i);

	if (i.battery_percentage == 0) {
		device_property_atomic_update_begin ();
		hal_device_property_remove (d, "battery.is_rechargeable");
		hal_device_property_remove (d, "battery.rechargeable.is_charging");
		hal_device_property_remove (d, "battery.rechargeable.is_discharging");
		hal_device_property_remove (d, "battery.charge_level.unit");
		hal_device_property_remove (d, "battery.charge_level.current");
		hal_device_property_remove (d, "battery.charge_level.maximum");
		device_property_atomic_update_end ();		
	} else {
		device_property_atomic_update_begin ();
		hal_device_property_set_bool (d, "battery.is_rechargeable", TRUE);
		hal_device_property_set_bool (d, "battery.present", TRUE);
		hal_device_property_set_int (d, "battery.charge_level", i.battery_percentage);
		hal_device_property_set_string (d, "battery.charge_level.unit", "percent");

		hal_device_property_set_int (d, "battery.charge_level.maximum", 100);

		/* TODO: clean the logic below up; it appears my T41
		 * with 2.6.10-1.1110_FC4 and acpi=off always report
		 * BATTERY_CHARGING so look at ac_line_status
		 * instead..
		 */
		if (i.battery_status == BATTERY_CHARGING) {
			hal_device_property_set_bool (d, "battery.rechargeable.is_charging", TRUE);
			hal_device_property_set_bool (d, "battery.rechargeable.is_discharging", FALSE);
		}
		else {
			hal_device_property_set_bool (d, "battery.rechargeable.is_charging", FALSE);
			hal_device_property_set_bool (d, "battery.rechargeable.is_discharging", i.ac_line_status == FALSE);
		}

		device_property_atomic_update_end ();
	}

	return TRUE;
}

static gboolean
ac_adapter_refresh (HalDevice *d, APMDevHandler *handler)
{
	const char *path;
	APMInfo i;

	path = hal_device_property_get_string (d, "linux.apm_path");
	if (path == NULL)
		return FALSE;

	hal_device_property_set_string (d, "info.product", "AC Adapter");
	hal_device_property_set_string (d, "info.category", "system.ac_adapter");
	hal_device_add_capability (d, "system.ac_adapter");

	read_from_apm(path, &i);

	if (i.ac_line_status)
		hal_device_property_set_bool (d, "ac_adapter.present", TRUE);
	else
		hal_device_property_set_bool (d, "ac_adapter.present", FALSE);

	return TRUE;
}

/** Scan the data structures exported by the kernel and add hotplug
 *  events for adding APM objects.
 *
 *  @param                      TRUE if, and only if, APM capabilities
 *                              were detected
 */
gboolean
apm_synthesize_hotplug_events (void)
{
	gboolean ret;
	HalDevice *computer;
	gchar path[HAL_PATH_MAX];
	HotplugEvent *hotplug_event;

	ret = FALSE;

	if (!g_file_test ("/proc/apm", G_FILE_TEST_EXISTS))
		goto out;

	ret = TRUE;

	if ((computer = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer")) == NULL) {
		HAL_ERROR (("No computer object?"));
		goto out;
	}

	/* Set appropriate properties on the computer object */
	hal_device_property_set_bool (computer, "power_management.is_enabled", TRUE);
	hal_device_property_set_string (computer, "power_management.type", "apm");

	snprintf (path, sizeof (path), "%s/apm", hal_proc_path);

	hotplug_event = g_new0 (HotplugEvent, 1);
	hotplug_event->is_add = TRUE;
	hotplug_event->type = HOTPLUG_EVENT_APM;
	g_strlcpy (hotplug_event->apm.apm_path, path, sizeof (hotplug_event->apm.apm_path));
	hotplug_event->apm.apm_type = APM_TYPE_BATTERY;
	hotplug_event_enqueue (hotplug_event);

	hotplug_event = g_new0 (HotplugEvent, 1);
	hotplug_event->is_add = TRUE;
	hotplug_event->type = HOTPLUG_EVENT_APM;
	g_strlcpy (hotplug_event->apm.apm_path, path, sizeof (hotplug_event->apm.apm_path));
	hotplug_event->apm.apm_type = APM_TYPE_AC_ADAPTER;
	hotplug_event_enqueue (hotplug_event);

out:
	return ret;
}

static HalDevice *
apm_generic_add (const gchar *apm_path, HalDevice *parent, APMDevHandler *handler)
{
	HalDevice *d;
	d = hal_device_new ();
	hal_device_property_set_string (d, "linux.apm_path", apm_path);
	hal_device_property_set_int (d, "linux.apm_type", handler->apm_type);
	if (parent != NULL)
		hal_device_property_set_string (d, "info.parent", parent->udi);
	else
		hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/computer");
	if (handler->refresh == NULL || !handler->refresh (d, handler)) {
		g_object_unref (d);
		d = NULL;
	}
	return d;
}

static gboolean
apm_generic_compute_udi (HalDevice *d, APMDevHandler *handler)
{
	gchar udi[256];
	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
			      "/org/freedesktop/Hal/devices/apm_%d",
			      hal_device_property_get_int (d, "linux.apm_type"));
	hal_device_set_udi (d, udi);
	hal_device_property_set_string (d, "info.udi", udi);
	return TRUE;
}

static gboolean
apm_generic_remove (HalDevice *d, APMDevHandler *handler)
{
	if (!hal_device_store_remove (hald_get_gdl (), d)) {
		HAL_WARNING (("Error removing device"));
	}

	return TRUE;
}

static APMDevHandler apmdev_handler_battery = { 
	.apm_type    = APM_TYPE_BATTERY,
	.add         = apm_generic_add,
	.compute_udi = apm_generic_compute_udi,
	.refresh     = battery_refresh,
	.remove      = apm_generic_remove
};

static APMDevHandler apmdev_handler_ac_adapter = { 
	.apm_type    = APM_TYPE_AC_ADAPTER,
	.add         = apm_generic_add,
	.compute_udi = apm_generic_compute_udi,
	.refresh     = ac_adapter_refresh,
	.remove      = apm_generic_remove
};

static APMDevHandler *apm_handlers[] = {
	&apmdev_handler_battery,
	&apmdev_handler_ac_adapter,
	NULL
};

void
hotplug_event_begin_add_apm (const gchar *apm_path, int apm_type, HalDevice *parent, void *end_token)
{
	guint i;

	HAL_INFO (("apm_add: apm_path=%s apm_type=%d, parent=0x%08x", apm_path, apm_type, parent));

	for (i = 0; apm_handlers [i] != NULL; i++) {
		APMDevHandler *handler;

		handler = apm_handlers[i];
		if (handler->apm_type == apm_type) {
			HalDevice *d;

			d = handler->add (apm_path, parent, handler);
			if (d == NULL) {
				/* didn't find anything - thus, ignore this hotplug event */
				hotplug_event_end (end_token);
				goto out;
			}

			hal_device_property_set_int (d, "linux.hotplug_type", HOTPLUG_EVENT_APM);

			/* Add to temporary device store */
			hal_device_store_add (hald_get_tdl (), d);

			/* Merge properties from .fdi files */
			di_search_and_merge (d);

			/* TODO: Run callouts */
			
			/* Compute UDI */
			if (!handler->compute_udi (d, handler)) {
				hal_device_store_remove (hald_get_tdl (), d);
				hotplug_event_end (end_token);
				goto out;
			}

			/* Move from temporary to global device store */
			hal_device_store_remove (hald_get_tdl (), d);
			hal_device_store_add (hald_get_gdl (), d);
			
			hotplug_event_end (end_token);
			goto out;
		}
	}
	
	/* didn't find anything - thus, ignore this hotplug event */
	hotplug_event_end (end_token);
out:
	;
}

void
hotplug_event_begin_remove_apm (const gchar *apm_path, int apm_type, void *end_token)
{
	guint i;
	HalDevice *d;

	HAL_INFO (("apm_rem: apm_path=%s apm_type=%d", apm_path, apm_type));

	d = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.apm_path", apm_path);
	if (d == NULL) {
		HAL_WARNING (("Couldn't remove device with apm path %s - not found", apm_path));
		goto out;
	}

	for (i = 0; apm_handlers [i] != NULL; i++) {
		APMDevHandler *handler;

		handler = apm_handlers[i];
		if (handler->apm_type == apm_type) {
			if (handler->remove (d, handler)) {
				hotplug_event_end (end_token);
				goto out2;
			}
		}
	}
out:
	/* didn't find anything - thus, ignore this hotplug event */
	hotplug_event_end (end_token);
out2:
	;
}

gboolean
apm_rescan_device (HalDevice *d)
{
	guint i;
	gboolean ret;
	int apm_type;

	ret = FALSE;

	apm_type = hal_device_property_get_int (d, "linux.apm_type");

	for (i = 0; apm_handlers [i] != NULL; i++) {
		APMDevHandler *handler;

		handler = apm_handlers[i];
		if (handler->apm_type == apm_type) {
			ret = handler->refresh (d, handler);
			goto out;
		}
	}

	HAL_WARNING (("Didn't find a rescan handler for udi %s", d->udi));

out:
	return ret;
}

HotplugEvent *
apm_generate_add_hotplug_event (HalDevice *d)
{
	int apm_type;
	const char *apm_path;
	HotplugEvent *hotplug_event;

	apm_path = hal_device_property_get_string (d, "linux.apm_path");
	apm_type = hal_device_property_get_int (d, "linux.apm_type");

	hotplug_event = g_new0 (HotplugEvent, 1);
	hotplug_event->is_add = TRUE;
	hotplug_event->type = HOTPLUG_EVENT_APM;
	g_strlcpy (hotplug_event->apm.apm_path, apm_path, sizeof (hotplug_event->apm.apm_path));
	hotplug_event->apm.apm_type = apm_type;
	return hotplug_event;
}

HotplugEvent *
apm_generate_remove_hotplug_event (HalDevice *d)
{
	int apm_type;
	const char *apm_path;
	HotplugEvent *hotplug_event;

	apm_path = hal_device_property_get_string (d, "linux.apm_path");
	apm_type = hal_device_property_get_int (d, "linux.apm_type");

	hotplug_event = g_new0 (HotplugEvent, 1);
	hotplug_event->is_add = FALSE;
	hotplug_event->type = HOTPLUG_EVENT_APM;
	g_strlcpy (hotplug_event->apm.apm_path, apm_path, sizeof (hotplug_event->apm.apm_path));
	hotplug_event->apm.apm_type = apm_type;
	return hotplug_event;
}

--- NEW FILE: apm.h ---
/***************************************************************************
 * CVSID: $Id: apm.h,v 1.1 2005/02/03 00:24:42 david Exp $
 *
 * Copyright (C) 2005 Richard Hughes <richard at hughsie.com>
 * Copyright (C) 2005 David Zeuthen, Red Hat Inc., <davidz at redhat.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **************************************************************************/

#ifndef APM_H
#define APM_H

#include "../hald.h"
#include "hotplug.h"

gboolean apm_synthesize_hotplug_events (void);

void hotplug_event_begin_add_apm (const gchar *apm_path, int apm_type, HalDevice *parent, void *end_token);

void hotplug_event_begin_remove_apm (const gchar *apm_path, int apm_type, void *end_token);

gboolean apm_rescan_device (HalDevice *d);

HotplugEvent *apm_generate_add_hotplug_event (HalDevice *d);

HotplugEvent *apm_generate_remove_hotplug_event (HalDevice *d);

#endif /* APM_H */




More information about the hal-commit mailing list