Initial import

This commit is contained in:
Dan Ponte 2011-11-06 10:39:08 -05:00
commit 1be1cb79fe
4 changed files with 1044 additions and 0 deletions

4
Makefile Normal file
View File

@ -0,0 +1,4 @@
SRCS=isa_if.h bus_if.h device_if.h winb.c
KMOD=winb
.include <bsd.kmod.mk>

14
README Normal file
View File

@ -0,0 +1,14 @@
This is a FreeBSD kernel module to present winbond W837* series and similar hardware monitoring chip info
as sysctl OIDs. Large portions were taken from mbmon, which is (C)1999-2004 Yoshifumi R. Shimizu.
Type "make" to build the kernel module.
The included patch is for conky-1.4.1. To use it, the ${winb} directive
is used in .conkyrc. It takes one argument, the name of the sensor.
These include:
fan[123], temp[123], vc[01], v33, v50[pn], v12[pn]
Have fun.
-Dan <dcp1990@neptune.atopia.net>
http://www.theamigan.net/

340
conky_141_winb.diff Normal file
View File

@ -0,0 +1,340 @@
diff -ru conky-1.4.1-old/src/conky.c conky-1.4.1/src/conky.c
--- conky-1.4.1-old/src/conky.c Thu May 11 17:05:02 2006
+++ conky-1.4.1/src/conky.c Thu May 11 17:05:44 2006
@@ -64,6 +64,10 @@
static int selected_font = 0;
static int font_count = -1;
struct font_list *fonts = NULL;
+struct WBIO wbio;
+struct WBData wbdat;
+static short same_interval = 0;
+void init_mibs(void);
#ifdef XFT
@@ -786,6 +790,7 @@
OBJ_offset,
OBJ_voffset,
OBJ_alignr,
+ OBJ_winb,
OBJ_alignc,
OBJ_i2c,
#if defined(__linux__)
@@ -992,6 +997,10 @@
int connection_index; /* 0 to n-1 connections. */
} tcp_port_monitor;
#endif
+ struct {
+ struct WBIO *wbio;
+ int type;
+ } wb;
} data;
};
@@ -1895,6 +1904,15 @@
(void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
END OBJ(seti_credit, INFO_SETI) END
#endif
+ OBJ(winb, INFO_WINB)
+ char b1[64];
+ obj->data.wb.wbio = &wbio;
+ if(!arg) {
+ CRIT_ERR("winb needs arguments");
+ }
+ sscanf(arg, "%63s", b1);
+ obj->data.wb.type = winbond_get_type(b1);
+ END
#ifdef MPD
OBJ(mpd_artist, INFO_MPD)
END OBJ(mpd_title, INFO_MPD)
@@ -2278,6 +2296,18 @@
get_freq_dynamic(p, p_max_size, "%'.2f", 1000); /* pk */
}
}
+ OBJ(winb) {
+ float r;
+ if(!same_interval) {
+ fill_wbdata(&wbdat);
+ same_interval = 1;
+ }
+ r = get_winbond_inf(obj->data.wb.type, &wbdat, obj->data.wb.wbio->fahr);
+ if(r > 100 || r == 0)
+ snprintf(p, p_max_size, "%d", (int)r);
+ else
+ snprintf(p, p_max_size, "%.1f", r);
+ }
OBJ(adt746xcpu) {
get_adt746x_cpu(p, p_max_size); /* pk */
}
@@ -3504,6 +3534,8 @@
p = text_buffer;
+ same_interval = 0;
+
generate_text_internal(p, P_MAX_SIZE, text_objects, text_object_count, cur);
if (stuff_in_upper_case) {
@@ -5045,6 +5077,10 @@
CONF_ERR;
}
#endif
+ CONF("winb_fahr") {
+ if(strcasecmp(value, "yes") == 0)
+ wbio.fahr = 1;
+ }
#ifdef MPD
CONF("mpd_host") {
if (value)
@@ -5449,6 +5485,8 @@
struct sigaction act, oact;
g_signal_pending=0;
+ memset(&wbio, 0, sizeof(wbio));
+ init_mibs();
memset(&info, 0, sizeof(info) );
#ifdef TCP_PORT_MONITOR
Only in conky-1.4.1/src: conky.c.orig
diff -ru conky-1.4.1-old/src/conky.h conky-1.4.1/src/conky.h
--- conky-1.4.1-old/src/conky.h Thu May 11 17:05:02 2006
+++ conky-1.4.1/src/conky.h Thu May 11 17:05:47 2006
@@ -200,6 +200,7 @@
#ifdef BMPX
INFO_BMPX = 24,
#endif
+ INFO_WINB = 25,
};
@@ -453,6 +454,11 @@
struct fs_stat *prepare_fs_stat(const char *path);
void clear_fs_stats(void);
+void fill_wbdata(struct WBData *wbd);
+float get_winbond_inf(int type, struct WBData *wbd, short fahr);
+int winbond_get_type(char *st);
+
+
/* in mixer.c */
int mixer_init(const char *);
@@ -519,6 +525,32 @@
int get_mldonkey_status(mldonkey_config * config, mldonkey_info * info);
#endif
+enum wbsens {
+ WB_FAN1,
+ WB_FAN2,
+ WB_FAN3,
+ WB_TEMP1,
+ WB_TEMP2,
+ WB_TEMP3,
+ WB_VC0,
+ WB_VC1,
+ WB_V33,
+ WB_V50P,
+ WB_V50N,
+ WB_V12P,
+ WB_V12N
+};
+
+struct WBIO {
+ int fahr;
+};
+
+struct WBData {
+ float temp1, temp2, temp3;
+ int fan1, fan2, fan3;
+ float vc0, vc1, v33, v50p, v50n, v12p, v12n;
+};
+
/* in linux.c */
Only in conky-1.4.1/src: conky.h.orig
diff -ru conky-1.4.1-old/src/freebsd.c conky-1.4.1/src/freebsd.c
--- conky-1.4.1-old/src/freebsd.c Thu May 11 17:05:02 2006
+++ conky-1.4.1/src/freebsd.c Thu May 11 17:05:49 2006
@@ -753,6 +753,180 @@
#endif
+#define CM(a) if(strcasecmp(st, #a) == 0) { return WB_ ## a; }
+#define VCM(a) else if(strcasecmp(st, #a) == 0) { return WB_ ## a; }
+int winbond_get_type(st)
+ char *st;
+{
+ CM(FAN1)
+ VCM(FAN2)
+ VCM(FAN3)
+ VCM(TEMP1)
+ VCM(TEMP2)
+ VCM(TEMP3)
+ VCM(VC0)
+ VCM(VC1)
+ VCM(V33)
+ VCM(V50P)
+ VCM(V50N)
+ VCM(V12P)
+ VCM(V12N)
+ return 0;
+}
+
+float get_winbond_inf(type, wbd, fahr)
+ int type;
+ struct WBData *wbd;
+ short fahr;
+{
+ float trv;
+#define FAHR(x) ((x) * 1.8 + 32.0)
+ switch(type) {
+ case WB_FAN1:
+ trv = (float)wbd->fan1;
+ break;
+ case WB_FAN2:
+ trv = (float)wbd->fan2;
+ break;
+ case WB_FAN3:
+ trv = (float)wbd->fan3;
+ break;
+ case WB_TEMP1:
+ trv = wbd->temp1;
+ if(fahr)
+ trv = FAHR(trv);
+ break;
+ case WB_TEMP2:
+ trv = wbd->temp2;
+ if(fahr)
+ trv = FAHR(trv);
+ break;
+ case WB_TEMP3:
+ trv = wbd->temp3;
+ if(fahr)
+ trv = FAHR(trv);
+ break;
+ case WB_VC0:
+ trv = wbd->vc0;
+ break;
+ case WB_VC1:
+ trv = wbd->vc1;
+ break;
+ case WB_V33:
+ trv = wbd->v33;
+ break;
+ case WB_V50P:
+ trv = wbd->v50p;
+ break;
+ case WB_V50N:
+ trv = wbd->v50n;
+ break;
+ case WB_V12P:
+ trv = wbd->v12p;
+ break;
+ case WB_V12N:
+ trv = wbd->v12n;
+ break;
+ default:
+ trv = 0.0;
+ }
+
+ return trv;
+}
+#define TEMPFORM(n) (float)(n & 0xff) + 0.5 * ((n & 0xFF00) >> 15)
+struct mibs {
+ int temps[2][3];
+ int fans[2][3];
+ int volts[6][3];
+} mibs;
+
+#define HWB "hw.winbond."
+void init_mibs(void)
+{
+ size_t ts = 3;
+ sysctlnametomib(HWB "temp1_up", mibs.temps[0], &ts);
+ sysctlnametomib(HWB "temp2_up", mibs.temps[1], &ts);
+ sysctlnametomib(HWB "temp3_up", mibs.temps[2], &ts);
+ sysctlnametomib(HWB "fan1", mibs.fans[0], &ts);
+ sysctlnametomib(HWB "fan2", mibs.fans[1], &ts);
+ sysctlnametomib(HWB "fan3", mibs.fans[2], &ts);
+ sysctlnametomib(HWB "vc0_up", mibs.volts[0], &ts);
+ sysctlnametomib(HWB "vc1_up", mibs.volts[1], &ts);
+ sysctlnametomib(HWB "v33_up", mibs.volts[2], &ts);
+ sysctlnametomib(HWB "v50p_up", mibs.volts[3], &ts);
+ sysctlnametomib(HWB "v12p_up", mibs.volts[4], &ts);
+ sysctlnametomib(HWB "v12n_up", mibs.volts[5], &ts);
+ sysctlnametomib(HWB "v50n_up", mibs.volts[6], &ts);
+}
+#define TL 3
+void getTemp(t1, t2, t3)
+ float *t1, *t2, *t3;
+{
+ int tv;
+ size_t sz = sizeof(tv);
+
+ sysctl(mibs.temps[0], TL, &tv, &sz, NULL, 0);
+ *t1 = TEMPFORM(tv);
+ sysctl(mibs.temps[1], TL, &tv, &sz, NULL, 0);
+ *t2 = TEMPFORM(tv);
+ sysctl(mibs.temps[2], TL, &tv, &sz, NULL, 0);
+ *t3 = TEMPFORM(tv);
+}
+
+void getFanSp(f1, f2, f3)
+ int *f1, *f2, *f3;
+{
+ int tv;
+ size_t sz = sizeof(tv);
+
+ sysctl(mibs.fans[0], TL, &tv, &sz, NULL, 0);
+ *f1 = tv;
+ sysctl(mibs.fans[1], TL, &tv, &sz, NULL, 0);
+ *f2 = tv;
+#if 0 /* doesn't work */
+ sysctl(mibs.fans[2], TL, &tv, &sz, NULL, 0);
+#endif
+ sysctlbyname("hw.winbond.fan3", &tv, &sz, NULL, 0);
+ *f3 = tv;
+}
+
+void getVolt(vc0, vc1, v33, v50p, v50n, v12p, v12n)
+ float *vc0, *vc1, *v33, *v50p, *v50n, *v12p, *v12n;
+{
+ int tv;
+ size_t sz = sizeof(tv);
+
+ sysctl(mibs.volts[0], TL, &tv, &sz, NULL, 0);
+ *vc0 = tv * 0.016;
+ sysctl(mibs.volts[1], TL, &tv, &sz, NULL, 0);
+ *vc1 = tv * 0.016;
+ sysctl(mibs.volts[2], TL, &tv, &sz, NULL, 0);
+ *v33 = tv * 0.016;
+ sysctl(mibs.volts[3], TL, &tv, &sz, NULL, 0);
+ *v50p = tv * 0.016 * 1.68;
+ sysctl(mibs.volts[4], TL, &tv, &sz, NULL, 0);
+ *v12p = tv * 0.016 * 3.800;
+ sysctl(mibs.volts[5], TL, &tv, &sz, NULL, 0);
+ *v12n = (tv * 0.016 - 3.6 * 0.8056) / 0.1944; /* different for w8371d */
+ sysctl(mibs.volts[6], TL, &tv, &sz, NULL, 0);
+ *v50n = (tv * 0.016 - 3.6 * 0.6818) / 0.3182;
+}
+
+void fill_wbdata(wbd)
+ struct WBData *wbd;
+{
+ getTemp(&wbd->temp1, &wbd->temp2, &wbd->temp3);
+
+/* get fan speeds */
+
+ getFanSp(&wbd->fan1, &wbd->fan2, &wbd->fan3);
+
+/* get voltages */
+
+ getVolt(&wbd->vc0, &wbd->vc1, &wbd->v33, &wbd->v50p, &wbd->v50n, &wbd->v12p, &wbd->v12n);
+}
+
+
/* empty stub so conky links */
void free_all_processes(void)
{
Only in conky-1.4.1/src: freebsd.c.orig

686
winb.c Normal file
View File

@ -0,0 +1,686 @@
/*
* winb kernel module
* (C)2006 Dan Ponte. Under the 3-clause BSD license.
* Portions taken from mbmon. (C)1999-2004 Yoshifumi R. Shimizu.
* Builds under FreeBSD 6.1 and others
*/
#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h> /* uprintf */
#include <sys/errno.h>
#include <sys/param.h> /* defines used in kernel.h */
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <machine/cpufunc.h>
#include <isa/isavar.h>
#include "isa_if.h"
/*
* Load handler that deals with the loading and unloading of a KLD.
*/
#define IOP_ADDR 0x290
#define INDEX_REG_PORT (IOP_ADDR + 0x05)
#define DATA_PORT (IOP_ADDR + 0x06)
#define WAIT outb(0xEB,0x00)
#define LM75_ADDR_START 0x90 /* 0x90-0x9E (0x48-0x4F) */
#define LM75_ADDR_END 0x9E
#define WINBD_ADDR_START 0x50 /* 0x50-0x5E (0x28-0x2F) */
#define WINBD_ADDR_END 0x5E
#define ASUSM_ADDR_FIX 0xEE /* ASUS Mozart-2, 0xEE (0x77) only */
#define WINBD_CONFIG 0x40
#define WINBD_SMBADDR 0x48
#define WINBD_DEVCID 0x49
#define WINBD_CHIPID 0x58
#define WINBD_VENDEX 0x4E
#define WINBD_VENDID 0x4F
#define ANADM_VENDID 0x3E
/* temp nr=0,1,2; volt nr=0,...6; fan nr=0,1,2 */
#define WINBD_TEMP0 0x27
#define ASUSB_TEMP4 0x17
#define ASUSM_TEMP2 0x13
#define WINBD_TEMPADDR 0x4A
#define WINBD_VOLT(nr) (0x20 + (nr))
#define WINBD_FAN(nr) (0x28 + (nr))
#define WINBD_FANDIV 0x47
#define WINBD_REGPIN 0x4B
#define ASUSM_FANDIV 0xA1
#define ANADM_TEMPCFG 0x4B
#define WINB_INT_STAT2 0x42
#define WINBD_DIOSEL 0x59
#define WINBD_VMCTRL 0x5D
#define WINBD_chkRegNum 8
static int probed = 0;
/* Register checked for probing */
static int chkReg[] = {
0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4A, 0x4B,
0x4C, 0x4D, 0x4E, 0x4F,
0x56, 0x58, 0x59, 0x5D,
0x3E, 0x13, 0x17, 0xA1,
0x20, 0x22, 0x23, 0x24,
0x27, 0x29, 0x2A, 0x2B,
-1 };
enum winbond_chips {
NOSENSER,
W83781D,
W83782D,
W83783S,
W83791D,
W83627HF,
W83697HF,
WBUNKNOWN,
AS99127F,
ASB100,
ASM58,
LM78,
LM79,
ADM9240,
UNKNOWN
};
struct winb_softc {
enum winbond_chips wbdchipid;
enum winbond_chips wbdlmid;
int temp1_flag;
int temp2_flag;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *winbroot;
struct {
struct sysctl_oid *temp1, *temp2, *temp3;
struct sysctl_oid *fan1, *fan2, *fan3;
struct sysctl_oid *vc0, *vc1, *v33;
struct sysctl_oid *v50p, *v50n, *v12p, *v12n;
struct sysctl_oid *chassis;
struct sysctl_oid *f1duty, *f2duty;
struct sysctl_oid *pwrled;
} oids;
};
static int Read(int addr)
{
int ret;
outb(INDEX_REG_PORT, addr); WAIT;
ret = inb(DATA_PORT); WAIT;
return (ret & 0xFF);
}
static void Write(int addr, int value)
{
outb(INDEX_REG_PORT, addr); WAIT;
outb(DATA_PORT, value); WAIT;
}
static int ReadTemp1(void)
{
int ret;
Write(0x4E, 0x01); /* changing to bank 1 */
ret = Read(0x50) | (Read(0x51) << 8);
Write(0x4E, 0x00); /* returning to bank 0 */
return ret;
}
static int ReadTemp2(void)
{
int ret;
Write(0x4E, 0x02); /* changing to bank 2 */
ret = Read(0x50) | (Read(0x51) << 8);
Write(0x4E, 0x00); /* returning to bank 0 */
return ret;
}
static int chkReg_Probe(int Reg[])
{
int i, n, r, ret = 0;
for(i = 0; (r = Reg[i]) != -1; i++) {
n = Read(r);
if(n != 0xFF)
++ret;
}
return ret;
}
/*
* \retval 0xFFFF no sensor
* \retval other temperature
* no = 0,1,2
*/
#define FLOATIT
#ifdef FLOATIT
static int winbond_temp(int no, struct winb_softc *wbc)
{
int n = 0;
if (no < 0 || 2 < no)
return 0xFFFF;
if (no == 2 &&
(wbc->wbdchipid == W83783S || wbc->wbdchipid == W83697HF || wbc->wbdchipid == ASM58))
return 0xFFFF;
if (no == 0) {
n = Read(WINBD_TEMP0);
return n;
} else if (no == 1) {
if (!wbc->temp1_flag)
n = ReadTemp1();
#ifdef SYRS
} else if (no == 2 && !wbc->temp2_flag) {
#else
} else if (no == 2) {
if (wbc->wbdchipid == ASB100) {
if (!wbc->temp1_flag)
n = ReadTemp1();
} else if (!wbc->temp2_flag)
#endif
n = ReadTemp2();
}
if ((n & 0xFF) >= 0x80)
n = 0;
return n;
}
static int winbond_chassis(device_t dev)
{
int n;
Write(0x4E, 0x04); /* changing to bank 4 */
n = Read(0x5A); /* RT hardware status II */
if(n & 0x10 /* chassis bit */) {
return 1;
} else {
return 0;
}
/* NOTREACHED */
}
static void winbond_setduty(device_t dev, int fan2 /* if true, fan2 set and not fan1 */, int duty_cycle /* byte */)
{
Write(0x4E, 0x00); /* bank 0 */
Write(0x5A + (fan2 ? 1 : 0), duty_cycle);
}
static int winbond_getduty(device_t dev, int fan2)
{
Write(0x4E, 0x00); /* bank 0 */
return Read(0x5A + (fan2 ? 1 : 0));
}
static void winbond_clearchas(void)
{
int oldval;
outb(0x2E, 0x87);
outb(0x2E, 0x87); /* double write to enter "extended function mode" */
outb(0x2E, 0x07); /* point to LD# reg */
outb(0x2F, 0xA); /* select device number A */
outb(0x2E, 0xE6); /* select CRE6 */
oldval = inb(0x2F); /* get old value */
outb(0x2E, 0xE6); /* select CRE6 */
outb(0x2F, oldval | 0x40 /* status clear */); /* update CRE6 with whatever */
outb(0x2E, 0xE6); /* select CRE6 */
outb(0x2F, oldval); /* reclear that bit */
outb(0x2E, 0xAA); /* write AAh to exit extended mode */
}
static int winbond_getpwrled(device_t dev)
{
int val;
outb(0x2E, 0x87);
outb(0x2E, 0x87); /* double write to enter "extended function mode" */
outb(0x2E, 0x07); /* point to LD# reg */
outb(0x2F, 0x8); /* select device number 8 */
outb(0x2E, 0xF5); /* select CRE6 */
val = inb(0x2F); /* get old value */
outb(0x2E, 0xAA); /* write AAh to exit extended mode */
val >>= 6;
return val;
}
static void winbond_setpwrled(device_t dev, int nv)
{
int val, tor;
tor = nv & 0x3; /* grab first two bits */
tor <<= 6;
outb(0x2E, 0x87);
outb(0x2E, 0x87); /* double write to enter "extended function mode" */
outb(0x2E, 0x07); /* point to LD# reg */
outb(0x2F, 0x8); /* select device number 8 */
outb(0x2E, 0xF5); /* select CRF5 */
val = inb(0x2F); /* get old value */
outb(0x2E, 0xF5); /* select CRF5 */
outb(0x2F, (val & ~(0x3 << 6)) | tor); /* update CRE6 with whatever */
outb(0x2E, 0xAA); /* write AAh to exit extended mode */
}
/*
* \retval 0x0000FFFF no sensor
* no = 0,1,2,...,6
*/
static int winbond_volt(int no, struct winb_softc *wbc)
{
int n;
if (no < 0 || 6 < no)
return 0xFFFF;
if (wbc->wbdchipid == ASM58 && (no == 1 || no > 4))
return 0xFFFF;
if (wbc->wbdchipid == ADM9240 && (no > 5))
return 0xFFFF;
n = Read(WINBD_VOLT(no));
return n;
}
#endif
/*
Controlling Fan Divisor for 1st/2nd fans: CR = 0x47.
1st two bits for fan1, 2nd two bits for fan2
7 4 3 0
+-+-+-+-+-+-+-+-+ xx = 00,01,10,11 div1fac = 1,2,4,8
|y y|x x| VolID | yy = 00,01,10,11 div2fac = 1,2,4,8
+-+-+-+-+-+-+-+-+ initial values: xx=01, yy=01
Controlling Fan Divisor for 3rd fan: CR = 0x4B.
1st two bits for fan3
7 6 5 0
+-+-+-+-+-+-+-+-+
|z z| | zz = 00,01,10,11 div3fac = 1,2,4,8
+-+-+-+-+-+-+-+-+ initial values: zz=01
3rd fan divisor available for Winbond (not for LM78/79).
Bit 2 of Fan Divisor: CR = 0x5D (Winbond chips except 781D).
7 6 5 0
+-+-+-+-+-+-+-+-+
|z|y|x| | x, y, z for bit 2 of fan 1, 2, 3
+-+-+-+-+-+-+-+-+
*/
/*
* \retval 0xFFFF no sensor
* no = 0,1,2
*
* Clock is 22.5kHz (22,500 x 60 = 1350000 counts/minute)
*/
static int winbond_fanrpm(int no, struct winb_softc *wbc)
{
int r, n1 = 0x50, n2 = 0x40, n3 = 0x00;
static int div[3] = {1,1,1};
if (no < 0 || 2 < no)
return 0xFFFF;
if (no == 2
&& (wbc->wbdchipid == W83697HF || wbc->wbdchipid == ASM58
|| wbc->wbdchipid == ADM9240))
return 0xFFFF;
if (W83782D <= wbc->wbdchipid && wbc->wbdchipid <= W83697HF) {
n3 = Read(WINBD_VMCTRL); /* bit 2 */
}
if (no != 2) {
n1 = Read(WINBD_FANDIV); /* bit 0,1 */
div[0] = ((n1 >> 4) & 0x03) | ((n3 & 0x20) >> 3);
div[1] = (n1 >> 6) | ((n3 & 0x40) >> 4);
} else if (wbc->wbdchipid < LM78) {
n2 = Read(WINBD_REGPIN); /* bit 0,1 */
div[2] = (n2 >> 6) | ((n3 & 0x80) >> 5);
}
r = Read(WINBD_FAN(no));
if (r == 0xFF) {
/* change divisor for the sake of next call ! */
if (no != 2) {
if (div[no] < 3)
++(div[no]);
else
div[no] = 0;
r = (n1 & 0x0F) | ((div[0] & 0x03) << 4) | ((div[1] & 0x03) << 6);
Write(WINBD_FANDIV, r);
} else if (wbc->wbdchipid < LM78) {
if (div[no] < 3)
++(div[no]);
else
div[no] = 0;
r = (n2 & 0x3F) | ((div[2] & 0x03) << 6);
Write(WINBD_REGPIN, r);
}
if (W83782D <= wbc->wbdchipid && wbc->wbdchipid <= W83697HF) {
r = (n3 & 0x1F) | ((div[0] & 0x04) << 3) |
((div[1] & 0x04) << 4) | ((div[2] & 0x04) << 5);
Write(WINBD_VMCTRL, r);
}
return 0xFFFF;
} else if (r == 0) {
return 0xFFFF;
}
return 1350000 / (r * (1 << div[no]));
}
static int
winb_loader(struct module *m, int what, void *arg)
{
int err = 0;
switch (what) {
case MOD_LOAD: /* kldload */
uprintf("winb loaded.\n");
break;
case MOD_UNLOAD:
uprintf("winb unloaded.\n");
break;
default:
err = EINVAL;
break;
}
return(err);
}
static void winb_isa_identify(driver_t *dr, device_t dev)
{
struct winb_softc *wbc;
wbc = device_get_softc(dev);
}
static int winb_isa_probe (device_t dev)
{
int n, nd, nc, nvl, nvu, nvx, nva;
struct winb_softc *wbc;
wbc = device_get_softc(dev);
if(probed)
return ENXIO;
/* probe it */
if (chkReg_Probe(chkReg) < WINBD_chkRegNum)
return ENXIO;
nd = Read(WINBD_DEVCID) & 0xFE;
nc = Read(WINBD_CHIPID);
nvx = Read(WINBD_VENDEX);
Write(WINBD_VENDEX, 0x00);
nvl = Read(WINBD_VENDID);
Write(WINBD_VENDEX, 0x80);
nvu = Read(WINBD_VENDID);
nva = Read(ANADM_VENDID);
if (nvl == 0xA3 && nvu == 0x5C) { /* Winbond Chip */
switch (nc & 0xFE) {
case 0x10: /* 0x10 (or 0x11) */
wbc->wbdchipid = W83781D;
break;
case 0x20: /* 0x20 (or 0x21) 627HF */
case 0x90: /* 0x90 (or 0x91?) 627THF */
case 0x1A: /* 0x1A (??) 627THF-A */
wbc->wbdchipid = W83627HF;
break;
case 0x30: /* 0x30 (or 0x31) */
wbc->wbdchipid = W83782D;
if (nc == 0x31)
wbc->wbdchipid = AS99127F; /* very special, but ... */
break;
case 0x40: /* 0x40 (or 0x41) */
wbc->wbdchipid = W83783S;
break;
case 0x60: /* 0x60 (or 0x61) */
wbc->wbdchipid = W83697HF;
break;
case 0x70: /* 0x70 (or 0x71) */
wbc->wbdchipid = W83791D;
break;
default:
return ENXIO;
}
}
wbc->wbdlmid = wbc->wbdchipid;
n = Read(WINBD_TEMPADDR);
if (!(wbc->temp1_flag = (n & 0x08) >> 3)) {
if (ReadTemp1() == 0xFFFF) {
wbc->temp1_flag = 1; /* disable! */
}
}
if (!(wbc->temp2_flag = (n & 0x80) >> 7)) {
if (ReadTemp2() == 0xFFFF) {
wbc->temp2_flag = 1; /* disable! */
}
}
probed = 1;
/* return wbc->wbdchipid or something */
return 0;
}
#define WB_FAN_FNC(id, num) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err, val; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
val = winbond_fanrpm(num, wbc); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if(err) \
return err; \
return 0; \
}
#define WB_CHAS_FNC(id) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err, val, oval; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
oval = val = winbond_chassis(dev); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if((val == 2) && (oval != 2)) { \
winbond_clearchas(); \
device_printf(dev, "supposedly cleared chassis bit\n"); \
} \
if(err) \
return err; \
return 0; \
}
#define WB_PWRLED_FNC(id) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err, val, oval; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
oval = val = winbond_getpwrled(dev); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if(val <= 3 && val >= 0 && (val != oval)) { \
winbond_setpwrled(dev, val); \
} else if(val != oval) { \
return EPERM; \
} \
if(err) \
return err; \
return 0; \
}
#define WB_FANDUTY_FNC(id, n) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err, val, oval; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
oval = val = winbond_getduty(dev, n); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if(val != oval) { \
winbond_setduty(dev, n, val); \
} \
if(err) \
return err; \
return 0; \
}
#ifdef FLOATIT
#define WB_TEMP_FNC(id, num) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err; \
int val; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
val = winbond_temp(num, wbc); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if(err) \
return err; \
return 0; \
}
#define WB_VOLT_FNC(id, num) static int winb_ ## id ## _sysc(SYSCTL_HANDLER_ARGS) \
{ \
struct winb_softc *wbc; \
device_t dev; \
int err; \
int val; \
dev = oidp->oid_arg1; \
wbc = device_get_softc(dev); \
val = winbond_volt(num, wbc); \
err = sysctl_handle_int(oidp, &val, sizeof(val), req); \
if(err) \
return err; \
return 0; \
}
/* *vc0 = v[0], *vc1 = v[1];
* *v33 = v[2], *v50p = v[3], *v12p = v[4];
* *v12n = v[5], *v50n = v[6];
*/
#endif
WB_FAN_FNC(fan1, 0)
WB_FAN_FNC(fan2, 1)
WB_FAN_FNC(fan3, 2)
WB_TEMP_FNC(temp1, 0)
WB_TEMP_FNC(temp2, 1)
WB_TEMP_FNC(temp3, 2)
WB_VOLT_FNC(vc0, 0)
WB_VOLT_FNC(vc1, 1)
WB_VOLT_FNC(v33, 2)
WB_VOLT_FNC(v50p, 3)
WB_VOLT_FNC(v12p, 4)
WB_VOLT_FNC(v12n, 5)
WB_VOLT_FNC(v50n, 6)
WB_CHAS_FNC(chassis)
WB_FANDUTY_FNC(f1duty, 0)
WB_FANDUTY_FNC(f2duty, 1)
WB_PWRLED_FNC(pwrled)
static int winb_isa_attach (device_t dev)
{
int rc;
struct winb_softc *wbc;
wbc = device_get_softc(dev);
rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, WINBD_ADDR_START, WINBD_ADDR_END - WINBD_ADDR_START);
if(rc != 0) {
device_printf(dev, "set res error! rc %d\n", rc);
return ENXIO;
}
sysctl_ctx_init(&wbc->sysctl_ctx);
wbc->winbroot = SYSCTL_ADD_NODE(&wbc->sysctl_ctx, SYSCTL_STATIC_CHILDREN(_hw),
OID_AUTO, "winbond", CTLFLAG_RD, 0, "winbond monitoring");
#define ADDPR(oid,hand,type, t, desc) wbc->oids.oid = SYSCTL_ADD_PROC(&wbc->sysctl_ctx, SYSCTL_CHILDREN(wbc->winbroot), OID_AUTO, #oid, CTLTYPE_ ## type | \
CTLFLAG_RD, dev, sizeof(dev), hand, t, desc)
#define ADDPRW(oid,hand,type, t, desc) wbc->oids.oid = SYSCTL_ADD_PROC(&wbc->sysctl_ctx, SYSCTL_CHILDREN(wbc->winbroot), OID_AUTO, #oid, CTLTYPE_ ## type | \
CTLFLAG_RW, dev, sizeof(dev), hand, t, desc)
#define ADDUPR(oid,hand,type, t, desc) wbc->oids.oid = SYSCTL_ADD_PROC(&wbc->sysctl_ctx, SYSCTL_CHILDREN(wbc->winbroot), OID_AUTO, #oid "_up", CTLTYPE_ ## type | \
CTLFLAG_RD, dev, sizeof(dev), hand, t, desc)
ADDPR(fan1, winb_fan1_sysc, INT, "I", "Fan1");
ADDPR(fan2, winb_fan2_sysc, INT, "I", "Fan2");
ADDPR(fan3, winb_fan3_sysc, INT, "I", "Fan3");
ADDPRW(pwrled, winb_pwrled_sysc, INT, "I", "PWRLED");
ADDPRW(chassis, winb_chassis_sysc, INT, "I", "Chassis");
ADDPRW(f1duty, winb_f1duty_sysc, INT, "I", "Fan1Duty");
ADDPRW(f2duty, winb_f2duty_sysc, INT, "I", "Fan2Duty");
ADDUPR(temp1, winb_temp1_sysc, INT, "I", "Temp1");
ADDUPR(temp2, winb_temp2_sysc, INT, "I", "Temp2");
ADDUPR(temp3, winb_temp3_sysc, INT, "I", "Temp3");
ADDUPR(vc0, winb_vc0_sysc, INT, "I", "VC0");
ADDUPR(vc1, winb_vc1_sysc, INT, "I", "VC1");
ADDUPR(v33, winb_v33_sysc, INT, "I", "V3.3");
ADDUPR(v50p, winb_v50p_sysc, INT, "I", "V5.0+");
ADDUPR(v50n, winb_v50n_sysc, INT, "I", "V5.0-");
ADDUPR(v12p, winb_v12p_sysc, INT, "I", "V12+");
ADDUPR(v12n, winb_v12n_sysc, INT, "I", "V12-");
#undef ADDPR
return 0;
}
static int winb_isa_detach (device_t dev)
{
struct winb_softc *wbc;
wbc = device_get_softc(dev);
if(sysctl_ctx_free(&wbc->sysctl_ctx)) {
uprintf("can't free context");
return ENOTEMPTY;
} else {
bus_delete_resource(dev, SYS_RES_IOPORT, 0);
return 0;
}
/* NOTREACHED */
return 0;
}
/* Declare this module to the rest of the kernel */
/* table of supported bus methods */
static device_method_t winb_isa_methods[] = {
/* list all the bus method functions supported by the driver */
/* omit the unsupported methods */
DEVMETHOD(device_identify, winb_isa_identify),
DEVMETHOD(device_probe, winb_isa_probe),
DEVMETHOD(device_attach, winb_isa_attach),
DEVMETHOD(device_detach, winb_isa_detach),
{ 0, 0 }
};
static driver_t winb_isa_driver = {
"winb",
winb_isa_methods,
sizeof(struct winb_softc),
};
static devclass_t winb_devclass;
DRIVER_MODULE(winb, acpi, winb_isa_driver, winb_devclass, winb_loader, NULL);