All pastes #161646 Raw Edit

Mine

public text v1 · immutable
·published 2006-09-05 17:38 UTC
rendered paste body
/* update should also submit card number !! */
#include <dbus/dbus-glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "nvclock.h"

#define NVCLOCKD_VERSION 1

static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN;

static void lose (const char *str, ...)
{
	va_list args;

	va_start (args, str);

	vfprintf (stderr, str, args);
	fputc ('\n', stderr);

	va_end (args);

	exit (1);
}

static void lose_gerror (const char *prefix, GError *error) 
{
	lose ("%s: %s", prefix, error->message);
}

typedef struct NVClockObject NVClockObject;
typedef struct NVClockObjectClass NVClockObjectClass;

GType nvclockd_get_type (void);

#define CAP_GPU_CLOCK (1<<0)
#define CAP_MEM_CLOCK (1<<1)
#define CAP_BOARD_TEMP (1<<2)
#define CAP_GPU_TEMP (1<<3)
#define CAP_DUTY_CYCLE (1<<4)
#define CAP_FANSPEED (1<<5)
#define CAP_SMARTDIMMER (1<<6)

typedef struct {
	float gpu_clock;
	float mem_clock;

	int board_temp;
	int gpu_temp;

	float duty_cycle;
	int fanspeed;

	int smartdimmer;
} updates;

struct NVClockObject
{
	GObject parent;
};

struct NVClockObjectClass
{
	GObjectClass parent;
};

char *tmpname;

#define NVCLOCKD_TYPE_OBJECT		(nvclockd_get_type ())
#define NVCLOCKD_OBJECT(object)		(G_TYPE_CHECK_INSTANCE_CAST ((object), NVCLOCKD_TYPE_OBJECT, NVClockObject))
#define NVCLOCKD_OBJECT_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), NVCLOCKD_TYPE_OBJECT, NVClockObjectClass))
#define TEST_IS_OBJECT(object)		(G_TYPE_CHECK_INSTANCE_TYPE ((object), NVCLOCKD_TYPE_OBJECT))
#define TEST_IS_OBJECT_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), NVCLOCKD_TYPE_OBJECT))
#define NVCLOCKD_OBJECT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), NVCLOCKD_TYPE_OBJECT, NVClockObjectClass))

G_DEFINE_TYPE(NVClockObject, nvclockd, G_TYPE_OBJECT)

gboolean nvclockd_get_cards (NVClockObject *obj, guint32 *cards, GError **error);
gboolean nvclockd_get_card_name (NVClockObject *obj, guint32 card, gchar **name, GError **error);
gboolean nvclockd_get_capabilities(NVClockObject *obj, guint32 card, guint32 *caps, GError **error);

gboolean nvclockd_get_gpu_clock (NVClockObject *obj, guint32 card, gdouble *clock, GError **error);
gboolean nvclockd_get_memory_clock (NVClockObject *obj, guint32 card, gdouble *clock, GError **error);

gboolean nvclockd_get_board_temperature (NVClockObject *obj, guint32 card, guint32 *temperature, GError **error);
gboolean nvclockd_get_gpu_temperature (NVClockObject *obj, guint32 card, guint32 *temperature, GError **error);

gboolean nvclockd_get_fan_duty_cycle (NVClockObject *obj, guint32 card, gdouble *duty_cycle, GError **error);
gboolean nvclockd_set_fan_duty_cycle (NVClockObject *obj, guint32 card, gdouble duty_cycle, gdouble *new_duty_cycle, GError **error);
gboolean nvclockd_get_fan_speed (NVClockObject *obj, guint32 card, guint32 *rpm, GError **error);

gboolean nvclockd_get_smartdimmer (NVClockObject *obj, guint32 card, guint32 *level, GError **error);
gboolean nvclockd_set_smartdimmer (NVClockObject *obj, guint32 card, guint32 level, guint32 *new_level, GError **error);

gboolean nvclockd_get_version (NVClockObject *obj, guint32 *version, GError **error);

#define NVCLOCKD_CHECK_CAPS(x,y) if(!(nv_card->caps & (x))) { \
                            g_set_error (error, g_quark_from_static_string ("error"), 0, y); \
                            nvclockd_unlock(); \
                            return FALSE; } while(0)
#define NVCLOCKD_GET_CARD(x) ((x>>29) & 0x3)
#define NVCLOCKD_SET_CARD(x,y) x |= ((y & 0x3) << 29)

enum
{
        UPDATE_SIGNAL,
        LAST_SIGNAL
};
static guint nvclockd_signals[LAST_SIGNAL] = { 0 };

#include "example-signal-emitter-glue.h"

static int lock = 0;

/* NVClock isn't threadsafe only one card can be accessed at a time, so we need some locking */
inline void nvclockd_lock()
{
	while(lock)
	{
		g_usleep(1000);
	}
	lock = 1;
	
}

inline void nvclockd_unlock()
{
	lock = 0;
}

static void nvclockd_init (NVClockObject *obj)
{
	GError *error = NULL;
	DBusGConnection *bus;
	DBusGProxy *bus_proxy;
	guint request_name_result;

	dbus_g_object_type_install_info (NVCLOCKD_TYPE_OBJECT, &dbus_glib_nvclockd_object_info);

	bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
	if (!bus)
		lose_gerror ("Couldn't connect to session bus", error);

	bus_proxy = dbus_g_proxy_new_for_name (bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);

	if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
				G_TYPE_STRING, "org.nvclock",
				G_TYPE_UINT, 0,
				G_TYPE_INVALID,
				G_TYPE_UINT, &request_name_result,
				G_TYPE_INVALID))
		lose_gerror ("Failed to acquire org.nvclock", error);

	dbus_g_connection_register_g_object (bus, "/org/nvclock/object", G_OBJECT (obj));
	FILE *fp=fopen("/tmp/nvclockd.lock","w");
	fclose(fp);
}

static void nvclockd_class_init (NVClockObjectClass *klass)
{
	nvclockd_signals[UPDATE_SIGNAL] =
		g_signal_new ("update_notification_event",
		G_OBJECT_CLASS_TYPE (klass),
		G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
		0,
		NULL, NULL,
		g_cclosure_marshal_VOID__UINT,
		G_TYPE_NONE, 1, G_TYPE_UINT);
}

/* This function changes the internal nvclock nv_card object to the requested videocard.
 * Further it does a lot of error handling.
 */
gboolean nvclockd_set_card(guint32 card, GError **error)
{
	if(nvclock.num_cards == 0)
	{
		g_set_error (error, g_quark_from_static_string ("error"), 0, "no nvidia cards found in this system");
		nvclockd_unlock();
		return FALSE;
	}

	if(card >= nvclock.num_cards)
	{
		g_set_error (error, g_quark_from_static_string ("error"), 0, "invalid card");
		nvclockd_unlock();
		return FALSE;
	}

	if(card != nv_card->number)
	{
		if(!set_card(card))
		{
			gchar buf[80];
			g_set_error (error, g_quark_from_static_string ("error"), 0, buf);
			nvclockd_unlock();
			return FALSE;
		}
	}

	return TRUE;
}

/* Get the number of Nvidia videocards in the system */
gboolean nvclockd_get_cards (NVClockObject *obj, guint32 *cards, GError **error)
{
	*cards = nvclock.num_cards;
	return TRUE;
}

/* Get the card name */
gboolean nvclockd_get_card_name (NVClockObject *obj, guint32 card, gchar **name, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	*name = g_strdup(nv_card->card_name);
	nvclockd_unlock();
	return TRUE;
}

/* Get the capabilities of the videocard. The function translates NVClock's internal capabilities to NVClockD capabilities. */
gboolean nvclockd_get_capabilities(NVClockObject *obj, guint32 card, guint32 *caps, GError **error)
{
	int res = 0;
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	res = CAP_GPU_CLOCK | CAP_MEM_CLOCK;

	if(nv_card->caps & BOARD_TEMP_MONITORING)
		res |= CAP_BOARD_TEMP;
	if(nv_card->caps & GPU_TEMP_MONITORING)
		res |= CAP_GPU_TEMP;
	if(nv_card->caps & GPU_FANSPEED_MONITORING)
		res |= CAP_DUTY_CYCLE;
	if(nv_card->caps & I2C_FANSPEED_MONITORING)
		res |= CAP_DUTY_CYCLE | CAP_FANSPEED;
	if(nv_card->caps & SMARTDIMMER)
		res |= CAP_SMARTDIMMER;

	*caps = res;
	nvclockd_unlock();
	return TRUE;
}

/* Get the GPU clockspeed in MHz */
gboolean nvclockd_get_gpu_clock (NVClockObject *obj, guint32 card, gdouble *clock, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	*clock = nv_card->get_gpu_speed();
	nvclockd_unlock();
	return TRUE;
}

/* Get the memory clockspeed in MHz */
gboolean nvclockd_get_memory_clock (NVClockObject *obj, guint32 card, gdouble *clock, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	*clock = nv_card->get_memory_speed();
	nvclockd_unlock();
	return TRUE;
}

/* Get the temperature of the videocard in degrees Celsius. This is supported on most cards containing an external sensor chip. */
gboolean nvclockd_get_board_temperature (NVClockObject *obj, guint32 card, guint *temperature, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(BOARD_TEMP_MONITORING, "Board temperature monitoring isn't support on this card");

	*temperature = nv_card->get_board_temp(nv_card->sensor);
	nvclockd_unlock();
	return TRUE;
}

/* Get the temperature of the GPU in degrees Celsius. This is supported on most Geforce6/7 cards and on cards containing sensor chips. */
gboolean nvclockd_get_gpu_temperature (NVClockObject *obj, guint32 card, guint32 *temperature, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(GPU_TEMP_MONITORING, "GPU temperature monitoring isn't support on this card");

	*temperature = nv_card->get_gpu_temp(nv_card->sensor);
	nvclockd_unlock();
	return TRUE;
}

/* Get the duty cycle of the GPU fan in %. This is supported on most GeforceFX/6/7 cards and on most cards containing sensor chips. */
gboolean nvclockd_get_fan_duty_cycle (NVClockObject *obj, guint32 card, gdouble *duty_cycle, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(GPU_FANSPEED_MONITORING | I2C_FANSPEED_MONITORING, "Fan duty cycle monitoring isn't support on this card");

	if(nv_card->caps & I2C_FANSPEED_MONITORING)
		*duty_cycle = nv_card->get_i2c_fanspeed_pwm(nv_card->sensor);
	else
		*duty_cycle = nv_card->get_fanspeed();

	nvclockd_unlock();
	return TRUE;
}

/* Set the duty cycle of the GPU fan in %. This is supported on most GeforceFX/6/7 cards and on most cards containing sensor chips. */
gboolean nvclockd_set_fan_duty_cycle (NVClockObject *obj, guint32 card, gdouble duty_cycle, gdouble *new_duty_cycle, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(GPU_FANSPEED_MONITORING | I2C_FANSPEED_MONITORING, "Fan duty cycle adjusting isn't support on this card");

	if(nv_card->caps & I2C_FANSPEED_MONITORING)
	{
		nv_card->set_i2c_fanspeed_pwm(nv_card->sensor, duty_cycle);
		*new_duty_cycle = nv_card->get_i2c_fanspeed_pwm(nv_card->sensor);
	}
	else
	{
		nv_card->set_fanspeed(duty_cycle);
		*new_duty_cycle = nv_card->get_fanspeed();
	}

	nvclockd_unlock();
	return TRUE;
}

/* Get the speed of the GPU fan in rpm. This is supported on some Geforce cards using advanced sensor chips like the ADT7473/F75375S */
gboolean nvclockd_get_fan_speed (NVClockObject *obj, guint32 card, guint32 *rpm, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(I2C_FANSPEED_MONITORING, "Fanspeed monitoring isn't support on this card");

	*rpm = nv_card->get_i2c_fanspeed_rpm(nv_card->sensor);
	nvclockd_unlock();
	return TRUE;
}

/* Get the Smartdimmer brightness level of the display. This is supported on some Geforce6/7 laptops */
gboolean nvclockd_get_smartdimmer (NVClockObject *obj, guint32 card, guint32 *level, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(SMARTDIMMER, "Smartdimmer isn't support on this card");
	*level = nv_card->get_smartdimmer();
	nvclockd_unlock();
	return TRUE;
}

/* Set the Smartdimmer brightness level of the display. This is supported on some Geforce6/7 laptops */
gboolean nvclockd_set_smartdimmer (NVClockObject *obj, guint32 card, guint32 level, guint32 *new_level, GError **error)
{
	nvclockd_lock();
	if(!nvclockd_set_card(card, error))
		return FALSE;

	NVCLOCKD_CHECK_CAPS(SMARTDIMMER, "Smartdimmer isn't support on this card");
	nv_card->set_smartdimmer(level);
	*new_level = nv_card->get_smartdimmer();
	nvclockd_unlock();
	return TRUE;
}

gboolean nvclockd_get_version (NVClockObject *obj, guint32 *version, GError **error)
{
    *version = NVCLOCKD_VERSION;
    return TRUE;
}


/* This function monitors the clockspeed/temperature/CAP_FANSPEED changes.
 * When a variable has changed it sends an update notification after which the client
 * needs to retrieve the variable again if it wants the updated value.
 */
gboolean nvclockd_update_callback(gpointer data)
{
	NVClockObject* obj = NVCLOCKD_OBJECT(data);
	static updates *cards;
	static int init=0;
	int i;

	if(!init)
	{
		cards = calloc(0, nvclock.num_cards * sizeof(updates));
		init=1;
	}
	nvclockd_lock();

	for(i=0; i<nvclock.num_cards; i++)
	{
		int changes = 0;
		float clock;
		set_card(i);

		clock = nv_card->get_gpu_speed();
		if(cards[i].gpu_clock != clock)
		{
			cards[i].gpu_clock = clock;
			changes |= CAP_GPU_CLOCK;
		}

		clock = nv_card->get_memory_speed();
		if(cards[i].mem_clock != clock)
		{
			cards[i].mem_clock = clock;
			changes |= CAP_MEM_CLOCK;
		}

		if(nv_card->caps & BOARD_TEMP_MONITORING)
		{
			int board_temp = nv_card->get_board_temp(nv_card->sensor);
			if(cards[i].board_temp != board_temp)
			{
				cards[i].board_temp = board_temp;
				changes |= CAP_BOARD_TEMP;
			}
			/* I2C bus reading increases cpu usage if we do it quickly after the previous read for some reason */
			g_usleep(1000);
		}

		if(nv_card->caps & GPU_TEMP_MONITORING)
		{
			int gpu_temp = nv_card->get_gpu_temp(nv_card->sensor);
			if(cards[i].gpu_temp != gpu_temp)
			{
				cards[i].gpu_temp = gpu_temp;
				changes |= CAP_GPU_TEMP;
			}
			/* I2C bus reading increases cpu usage if we do it quickly after the previous read for some reason */
			g_usleep(1000);
		}

		if(nv_card->caps & GPU_FANSPEED_MONITORING)
		{
			float duty_cycle = nv_card->get_fanspeed();
			if(cards[i].duty_cycle != duty_cycle)
			{
				cards[i].duty_cycle = duty_cycle;
				changes |= CAP_DUTY_CYCLE;
			}
			/* I2C bus reading increases cpu usage if we do it quickly after the previous read for some reason */
			g_usleep(1000);
		}

		if(nv_card->caps & I2C_FANSPEED_MONITORING)
		{
			float duty_cycle = nv_card->get_i2c_fanspeed_pwm(nv_card->sensor);
			int fanspeed = nv_card->get_i2c_fanspeed_rpm(nv_card->sensor);
			if(cards[i].duty_cycle != duty_cycle)
			{
				cards[i].duty_cycle = duty_cycle;
				changes |= CAP_DUTY_CYCLE;
			}
			if(cards[i].fanspeed != fanspeed)
			{
				cards[i].fanspeed = fanspeed;
				changes |= CAP_FANSPEED;
			}
			/* I2C bus reading increases cpu usage if we do it quickly after the previous read for some reason */
			g_usleep(1000);
		}

		if(nv_card->caps & SMARTDIMMER)
		{
			int smartdimmer = nv_card->get_smartdimmer();
			if(cards[i].smartdimmer != smartdimmer)
			{
				cards[i].smartdimmer = smartdimmer;
				changes |= CAP_SMARTDIMMER;
			}
		}

		if(changes)
		{
			/* D-BUS doesn't provide a void__uint_uint marshaller by default, further messing with arrays might
			 * be relatively complex for dbus clients (depending on the language), so for now store the card number
			 * in the two highest bits which is what the macro does.
			 */
			NVCLOCKD_SET_CARD(changes, i);
			g_signal_emit(obj, nvclockd_signals[UPDATE_SIGNAL], 0, changes);
		}
	}

	nvclockd_unlock();
	return TRUE;
}

void nvclockd_cleanup() {
	unlink("/tmp/nvclockd.lock");
	exit (0);
}

int main (int argc, char **argv)
{
	NVClockObject *obj;
	GMainLoop *mainloop;

	g_type_init ();
	
	mainloop = g_main_loop_new (NULL, FALSE);

	obj = g_object_new (NVCLOCKD_TYPE_OBJECT, NULL);

	if(!init_nvclock())
	{
		char buf[80];
		printf("Error: %s\n", get_error(buf, 80));
	}
	else
		set_card(0);
	
	/*signals for lockfile*/
	signal(SIGINT, nvclockd_cleanup);
    	signal(SIGSEGV, nvclockd_cleanup);
    	signal(SIGQUIT, nvclockd_cleanup);
    	signal(SIGTERM, nvclockd_cleanup);
    	signal(SIGHUP, nvclockd_cleanup); 

	/* Update thread */
	g_timeout_add (200, (GSourceFunc) nvclockd_update_callback, obj);

	g_main_loop_run (mainloop);

 	nvclockd_cleanup();
	return 0;
}