/*
 Motherboard hardware monitor driver
 
 Copyright (c) 2008 Dimtel, Inc., All Rights Reserved

 $Id: hwmon.c,v 1.4 2011/12/28 09:43:18 dim Exp $
 $Date: 2011/12/28 09:43:18 $
 $Author: dim $
 $Revision: 1.4 $
 $Log: hwmon.c,v $
 Revision 1.4  2011/12/28 09:43:18  dim
 Added board_name detection method to existing product_name

 Revision 1.3  2011/12/07 19:18:25  dim
 Renamed poll.c to hwpoll.c, changed detection to /sys/class/dmi/id/product_name

 Revision 1.2  2010/10/05 16:15:58  dim
 Removed extraneous files, updates for Gigabyte MB

 Revision 1.1  2009/02/05 07:29:09  dim
 Initial import of motherboard hardware monitoring driver


*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include "hwmon.h"

static char _hwmon_buf[HWMON_BUF];
static char _hwmon_path[HWMON_BUF];
static char *_hwmon_name;

#define deltaT(tvp1, tvp2) (((tvp2)->tv_sec-(tvp1)->tv_sec)*1000000 + \
			      (tvp2)->tv_usec - (tvp1)->tv_usec)

static hwmon_device _hwmon_device_defs[] = {
/* Via VB7001G */
{"CN700-8237R",  "fan2_input", "fan1_input", "temp2_input"},
/* Via VB7002G */
{"CN896-8237S",  "fan2_input", "fan1_input", "temp2_input"},
/* Via VB8001G */
{"CN896-8237S",  "fan2_input", "fan1_input", "temp2_input"},
/* Jetway J7F2 */
{"CN700-8237", "fan1_input", "fan3_input", "temp1_input"},
/* Jetway J7F5 */
{"CX700", "fan1_input", "fan3_input", "temp1_input"},
/* Intel D510MO */
{"w83627thf", "fan2_input", "fan1_input", "temp1_input"},
/* Gigabyte GA-6KIEH-RH */
{"GA-6KIEH-RH", "fan1_input", "fan2_input", "temp2_input"},
/* MSI IM-GM45 */
{"MS-9818", "fan2_input", "fan3_input", "temp2_input"},
/* BCM MX965GME */
{"MX965GME", "fan1_input", "fan2_input", "temp2_input"},
/* BCM MX45GM2 */
{"MX45GM2", "fan2_input", "fan1_input", "temp2_input"}};

static int _hwmon_device_idx = -1;

int hwmon_init(void)
{
  int k, defs;
  
  defs = sizeof(_hwmon_device_defs)/sizeof(hwmon_device);

  if (_hwmon_device_idx == -1) /* Not initialized yet */
  {
    strcpy(_hwmon_path, DMI_PATH);
    strcat(_hwmon_path, "product_name");
    
    /* Read driver name */
    int fd;
    if ((fd = open(_hwmon_path, O_RDONLY)) < 0)
      return -1;
    
    k = read(fd, _hwmon_buf, HWMON_BUF);
    close(fd);
    if (k < 0)
      return -1;
    
    if (strlen(_hwmon_buf) <= 2) /* Not filled out, use board_name */
    {
      strcpy(_hwmon_path, DMI_PATH);
      strcat(_hwmon_path, "board_name");
    
      /* Read driver name */
      if ((fd = open(_hwmon_path, O_RDONLY)) < 0)
        return -1;
    
      k = read(fd, _hwmon_buf, HWMON_BUF);
      close(fd);
      if (k < 0)
        return -1;
    }
    
    /* Process the name */
    for (k = 0; k < defs; k++)
    {
      if (strncmp(_hwmon_buf, _hwmon_device_defs[k].name, 
          strlen(_hwmon_device_defs[k].name)) == 0)
        break;
    }
    
    if (k < defs) /* Otherwise the idx stays at -1 */
      _hwmon_device_idx = k;

    strcpy(_hwmon_path, BASE_PATH);
    _hwmon_name = _hwmon_path + strlen(BASE_PATH);
  }
  
  return _hwmon_device_idx;
}

int hwmon_read_raw(char *name)
{
  int fd, count;

  memcpy(_hwmon_name, name, strlen(name)+1);
  fd = open(_hwmon_path, O_RDONLY);
  if (fd == -1)
    return -1;
  count = read(fd, _hwmon_buf, HWMON_BUF);
  close(fd);
  return count;
}

int hwmon_read(hwmon_data *data)
{
#ifdef DEBUG
  struct timeval t1, t2;
  gettimeofday(&t1, NULL);
#endif
  
  /* Check if we are initialized */
  if (_hwmon_device_idx < 0)
    return -1;
    
  if (hwmon_read_raw(_hwmon_device_defs[_hwmon_device_idx].cpu_fan) < 0)
    return -1;
  
  /* Process the CPU fan speed */
  data->cpu_fan = atoi(_hwmon_buf);

  if (hwmon_read_raw(_hwmon_device_defs[_hwmon_device_idx].chassis_fan) < 0)
    return -1;
  
  /* Process the chassis fan speed */
  data->chassis_fan = atoi(_hwmon_buf);
  
  if (hwmon_read_raw(_hwmon_device_defs[_hwmon_device_idx].cpu_temp) < 0)
    return -1;
  
  /* Process the CPU temperature */
  data->cpu_temp = (double)atoi(_hwmon_buf)/1000.0;

#ifdef DEBUG
  gettimeofday(&t2, NULL);
  int diff = deltaT(&t1, &t2);
  printf("hwmon_read(): %.3f ms\n", ((double)diff)/1000.0);
#endif
  return 0;
}
