/*
 * Copyright (c) 1999
 *         Chris D. Faulhaber <jedgar@fxp.org>.  All rights reserved.
 *  
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer as
 *    the first lines of this file unmodified.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  
 * THIS SOFTWARE IS PROVIDED BY CHRIS D. FAULHABER ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL CHRIS D. FAULHABER BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Portions of this software derived from examples (c) 1998 Takanori Watanabe.
 *
 *      $Id: wmlmmon.c,v 1.14 1999/11/03 00:27:31 jedgar Exp $
 */
              
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <machine/cpufunc.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <X11/Xlibint.h>

#ifdef HAVE_CONFIG_H
  #include "config.h"
#endif
#ifdef HAVE_SMB
  #include <machine/smb.h>
#endif

#include "wmgeneral.h"
#include "wmlmmon.h"
#include "wmlmmon-mask.xbm"
#include "wmlmmon-master.xpm"

void
usage()
{
	(void)fprintf(stderr, "%s%s\n%s\n",
		      "wmlmmon v", WMLMMON_VERSION,
		      "usage: wmlmmon [-cfhikv] [-d display]");
	exit(1);
}

u_char
get_data(int smbdev, u_char command, int interface)
{
	u_char return_val;

	return_val = 0;

#ifdef HAVE_SMB
	if (interface == INTERFACE_SMB) {
		struct smbcmd cmd;
		u_char byte;
 
		byte = 0;

		/* Initialize the struct */
		bzero(&cmd, sizeof(cmd));
		cmd.data.byte_ptr = &byte;
		cmd.slave         = 0x5a;
		cmd.cmd           = command;
 
		/* Send the command */
		if (ioctl(smbdev, SMB_READB, (caddr_t)&cmd) == -1) {
			perror("IOCTL");
			exit(1);
		}
 
		/* Return the value */
		return_val = byte;
	} else if (interface == INTERFACE_IO) {
#endif /* HAVE_SMB */
		outb(WBIO1, command);
		return_val = inb(WBIO2);
#ifdef HAVE_SMB
	}
#endif

	return return_val;
}

int
main(int argc, char *argv[])
{
	double voltage;
	char *device_name;
	int byte, ch, current, delay, digit, i, scale, smbdev;
	int fandiv[3], fanspeed, temperature, changed, interface;
	XEvent Event;

	changed   = 1;
	current   = DISPLAY_VOLT_2;
	delay     = DELAY;
	interface = INTERFACE_SMB;
	scale     = TEMP_C;

	/* Get command-line options */
	while ((ch = getopt(argc, argv, "cfhikvd:")) != -1)
		switch(ch) {
		case 'i':
			interface = INTERFACE_IO;
			break;
		case 'c':
			scale = TEMP_C;
			break;
		case 'f':
			scale = TEMP_F;
			break;
		case 'k':
			scale = TEMP_K;
			break;
		case 'd':
			break;
		default:
			usage();
			break;
		}
	argc -= optind;
	argv += optind;

	if (delay < 1)
		delay = 1;

#ifndef HAVE_SMB
	interface = INTERFACE_IO;
#endif

	/* Open the device */
	switch(interface) {
	case INTERFACE_SMB:
		device_name = SMB_DEV;
		break;
	default:
		device_name = IO_DEV;
		break;
	}

	if ((smbdev = open(device_name, O_RDWR)) == -1) {
		fprintf(stderr, "Failed to open device %s.\n", device_name);
		if (!strncmp(device_name, "/dev/smb", 8)) {
			fprintf(stderr, "If your system does not support intpm(4),\n");
			fprintf(stderr, "try to use /dev/io (-i flag) or check\n");
		} else {
			fprintf(stderr, "Check "); 
		}
		fprintf(stderr, "the permissions of %s.\n", device_name);
		exit(1);
	}

	/* Get fan divisors */
	byte      = get_data(smbdev, LM78_FANDIV, interface);
	fandiv[0] = LM78_DIV_FROM_DATA((byte >> 4) & 0x03);
	fandiv[1] = LM78_DIV_FROM_DATA(byte >> 6);
	fandiv[2] = LM78_DIV_FROM_DATA(1);

	/* Create the app image */
	openXwindow(argc, argv, wmlmmon_master_xpm, wmlmmon_mask_bits,
		    wmlmmon_mask_width, wmlmmon_mask_height);

	/* Add regions for mouse clicks */
	AddMouseRegion(0,  5,  5, 30, 19);
	AddMouseRegion(1, 34,  5, 59, 19);
	AddMouseRegion(2,  5, 17, 59, 59);

	/* Start our loop */
	while (1) {
		while(XPending(display)) {
			XNextEvent(display,&Event);
			switch (Event.type) {
			case Expose:
				RedrawWindow();
				break;
			case DestroyNotify:
				XCloseDisplay(display);
				close(smbdev);
				exit(0);
				break;
			case ButtonPress:
				i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
				switch(i) {
				case 1:
					scale = scale < 2 ? scale + 1 : 0;
					changed = 1;
					break;
				default:
					current = current < 2 ? current + 1 : 0;
					changed = 1;
					break;
				}
				break;
			}
		}

		/* Get motherboard temp */
		temperature = LM78_TEMP_FROM_DATA(get_data(smbdev, LM78_TEMP, interface), scale);
#ifdef DEBUG
		printf("MB temp:\n");
		printf("       ");
		printf("%i\n", temperature);
#endif
		if (changed)
			switch(scale) {
			case TEMP_C:
				copyXPMArea(13, 74, 5, 9, 53, 5);
				break;
			case TEMP_F:
				copyXPMArea( 1, 74, 5, 9, 53, 5);
				break;
			case TEMP_K:
				copyXPMArea( 7, 74, 5, 9, 53, 5);
				break;
			}

		digit = (int)(temperature % 10);	 		/* 1's digit */
		copyXPMArea((digit * 6) + 1, 64, 5, 9, 47, 5);
		digit = (int)((temperature % 100) - digit) / 10;	/* 10's digit */
		copyXPMArea((digit * 6) + 1, 64, 5, 9, 41, 5);
		digit = (int)((temperature % 1000) - digit) / 100;	/* 100's digit */
		if (digit)
			copyXPMArea((digit * 6) + 1, 64, 5, 9, 35, 5);
		else
			copyXPMArea(61, 64, 5, 9, 35, 5);

		switch(current) {
		case DISPLAY_FANS:
			if (changed) {
				/* Clean unused areas */
				copyXPMArea(27, 85, 23, 7,  6, 50);
				copyXPMArea(27, 85, 23, 7, 35, 50);
				copyXPMArea(68, 70,  3, 3, 31, 52);
				/* Show 'FANS' */
				copyXPMArea(43, 75, 23, 7,  6, 6);
			}
			/* Get fan speeds */
			for (i = 0; i < 3; i++) {
				fanspeed = LM78_FAN_FROM_DATA(get_data(smbdev, LM78_FAN(i),
								       interface), fandiv[i]);
#ifdef DEBUG
				printf("  %i : %4d rpm\n", i + 1, fanspeed);
#endif
				/* Clean unused areas */
				if (changed) {
					copyXPMArea(27, 85, 23, 7,  6, (i * 10) + 20);
					copyXPMArea(68, 70,  3, 3, 31, (i * 10) + 22);
					copyXPMArea(73, 64,  1, 2, 46, (i * 10) + 26);
				}
				copyXPMArea(73, 64,  1, 2, 46, 56);
				copyXPMArea((i + 1) * 6 + 1, 64, 5, 9, 16, (i * 10) + 19);
				digit = (int)(fanspeed % 10);
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 53, (i * 10) + 19);
				digit = (int)((fanspeed % 100) - digit) / 10;
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 47, (i * 10) + 19);
				digit = (int)((fanspeed % 1000) - digit) / 100;
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 41, (i * 10) + 19);
				digit = (int)(fanspeed - (fanspeed % 1000)) / 1000;
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 35, (i * 10) + 19);
			}
			break;
		case DISPLAY_VOLT_1:
			if (changed) {
				/* Clean unused areas */
				copyXPMArea(27, 85, 23, 7, 6, 50);
				copyXPMArea(27, 85, 23, 7, 35, 50);
				copyXPMArea(68, 70,  3, 3, 31, 52);
				/* Show 'VOLT' */
				copyXPMArea(19, 75, 23, 7, 6, 6);
			}
			/* Get voltages */
			for (i = 0; i < 3; i++) {
				int value;

				voltage = LM78_VOLT_FROM_DATA(get_data(smbdev, LM78_VOLT(i),
								       interface), i);
#ifdef DEBUG
				printf("  %i :%+8.3fV\n", i, voltage);
#endif
				/* Clean unused areas */
				if (changed) {
					copyXPMArea(27, 85, 23, 7, 6, (i * 10) + 20);
					copyXPMArea(1, 85, 23, 7,  6, 20); /* Core */
					copyXPMArea(1, 85, 23, 7,  6, 30); /* Core */
					copyXPMArea(68, 64, 3, 3,  7, 42); /* +3.3 */
					copyXPMArea(19, 65, 5, 7, 18, 40);
					copyXPMArea(19, 65, 5, 7, 24, 40);
					copyXPMArea(73, 68, 1, 2, 23, 46);
					copyXPMArea(73, 68, 1, 2, 46, (i * 10) + 26);
				}
				if (voltage < 0)
					copyXPMArea(68, 67, 3, 3, 31, (i * 10) + 22);
				else
					copyXPMArea(68, 64, 3, 3, 31, (i * 10) + 22);
				value = abs((int)(voltage * 100));
				digit = (int)(value % 10);			/* 1's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 53, (i * 10) + 19);
				digit = (int)((value % 100) - digit) / 10;	/* 10's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 47, (i * 10) + 19);
				digit = (int)((value % 1000) - digit) / 100;	/* 100's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 41, (i * 10) + 19);
				digit = (int)(value - (value % 1000)) / 1000;	/* 1000's */
				if (digit)
					copyXPMArea((digit * 6) + 1, 64, 5, 9, 35, (i * 10) + 19);
				else
					copyXPMArea(61, 64, 5, 9, 35, (i * 10) + 19);
			}
			break;
		case DISPLAY_VOLT_2:
			/* Get voltages */
			for (i = 0; i < 4; i++) {
				int value;

				voltage = LM78_VOLT_FROM_DATA(get_data(smbdev, LM78_VOLT(i + 3),
								       interface), i + 3);
#ifdef DEBUG
				printf("  %i :%+8.3fV\n", i, voltage);
#endif
				if (changed) {
					/* Show VOLT */
					copyXPMArea(19, 75, 23, 7, 6, 6);
					/* Show labels */
					copyXPMArea(27, 85, 23, 7, 6, (i * 10) + 20);
					copyXPMArea(68, 64, 3, 3,  7, 22); /* +5.0 */
					copyXPMArea(31, 65, 5, 7, 18, 20);
					copyXPMArea(73, 68, 1, 2, 23, 26);
					copyXPMArea( 1, 65, 5, 7, 24, 20);
					copyXPMArea(68, 64, 3, 3,  7, 32); /* +12.0 */
					copyXPMArea( 7, 65, 5, 7, 12, 30);
					copyXPMArea(13, 65, 5, 7, 18, 30);
					copyXPMArea(73, 68, 1, 2, 23, 36);
					copyXPMArea( 1, 65, 5, 7, 24, 30);
					copyXPMArea(68, 67, 3, 3,  7, 42); /* -12.0 */
					copyXPMArea( 7, 65, 5, 7, 12, 40);
					copyXPMArea(13, 65, 5, 7, 18, 40);
					copyXPMArea(73, 68, 1, 2, 23, 46);
					copyXPMArea( 1, 65, 5, 7, 24, 40);
					copyXPMArea(68, 67, 3, 3,  7, 52); /* -5.0 */
					copyXPMArea(31, 65, 5, 7, 18, 50);
					copyXPMArea(73, 68, 1, 2, 23, 56);
					copyXPMArea( 1, 65, 5, 7, 24, 50);
				}
				copyXPMArea(73, 68, 1, 2, 46, (i * 10) + 26);
				if (voltage < 0)
					copyXPMArea(68, 67, 3, 3, 31, (i * 10) + 22);
				else
					copyXPMArea(68, 64, 3, 3, 31, (i * 10) + 22);
				value = abs((int)(voltage * 100));
				digit = (int)(value % 10);			/* 1's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 53, (i * 10) + 19);
				digit = (int)((value % 100) - digit) / 10;	/* 10's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 47, (i * 10) + 19);
				digit = (int)((value % 1000) - digit) / 100;	/* 100's */
				copyXPMArea((digit * 6) + 1, 64, 5, 9, 41, (i * 10) + 19);
				digit = (int)(value - (value % 1000)) / 1000;	/* 1000's */
				if (digit)
					copyXPMArea((digit * 6) + 1, 64, 5, 9, 35, (i * 10) + 19);
				else
					copyXPMArea(61, 64, 5, 9, 35, (i * 10) + 19);
			}
			break;
		}

		RedrawWindow();
		changed = 0;
		sleep(delay);

	}

	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1