svn commit: r183751 - user/rpaulo/eeemon
Rui Paulo
rpaulo at FreeBSD.org
Fri Oct 10 17:53:27 UTC 2008
Author: rpaulo
Date: Fri Oct 10 17:53:26 2008
New Revision: 183751
URL: http://svn.freebsd.org/changeset/base/183751
Log:
eeemon is a kernel module for Asus Eee notebooks that allows you to
control the fan speed, high/low voltage and it shows the cpu
temperature.
Includes fan control code by "harrow at yandex.ru".
Imported from my peronal repo.
Added:
user/rpaulo/eeemon/
user/rpaulo/eeemon/Makefile (contents, props changed)
user/rpaulo/eeemon/eeemon.c (contents, props changed)
user/rpaulo/eeemon/eeemonreg.h (contents, props changed)
Added: user/rpaulo/eeemon/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ user/rpaulo/eeemon/Makefile Fri Oct 10 17:53:26 2008 (r183751)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD= eeemon
+SRCS= eeemon.c isa_if.h bus_if.h device_if.h
+
+.include <bsd.kmod.mk>
Added: user/rpaulo/eeemon/eeemon.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ user/rpaulo/eeemon/eeemon.c Fri Oct 10 17:53:26 2008 (r183751)
@@ -0,0 +1,305 @@
+/*-
+ * Copyright (c) 2008 Rui Paulo <rpaulo at FreeBSD.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.
+ * 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 THE AUTHOR ``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 THE AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+#include <machine/cpufunc.h>
+#include <machine/bus.h>
+
+#include "eeemonreg.h"
+
+enum {
+ EEEMON_TEMP,
+ EEEMON_FAN,
+ EEEMON_VOLT,
+ EEEMON_FANMANUAL,
+ EEEMON_FANSPEED
+};
+
+/*
+ * Device interface.
+ */
+static void eeemon_identify(driver_t *driver, device_t parent);
+static int eeemon_probe(device_t dev);
+static int eeemon_attach(device_t dev);
+static int eeemon_detach(device_t dev);
+static void eeemon_intrhook(void *arg);
+static int eeemon_match(void);
+static int eeemon_readbyte(uint16_t addr);
+static void eeemon_writebyte(uint16_t addr, uint8_t byte);
+static int eeemon_sysctl(SYSCTL_HANDLER_ARGS);
+
+struct eeemon_softc {
+ device_t sc_dev;
+ struct sysctl_oid *sc_sctl_cputemp;
+ struct sysctl_oid *sc_sctl_cpufan;
+ struct intr_config_hook sc_ich;
+};
+
+/*
+ * Driver methods.
+ */
+static device_method_t eeemon_methods[] = {
+ DEVMETHOD(device_identify, eeemon_identify),
+ DEVMETHOD(device_probe, eeemon_probe),
+ DEVMETHOD(device_attach, eeemon_attach),
+ DEVMETHOD(device_detach, eeemon_detach),
+
+ { 0, 0 }
+};
+
+static driver_t eeemon_driver = {
+ "eeemon",
+ eeemon_methods,
+ sizeof(struct eeemon_softc)
+};
+
+static devclass_t eeemon_devclass;
+
+DRIVER_MODULE(eeemon, isa, eeemon_driver, eeemon_devclass, 0, 0);
+
+static int
+eeemon_match(void)
+{
+ int i;
+ char *model;
+
+ model = getenv("smbios.system.serial");
+ i = 0;
+ if (strncmp(model, "EeePC", 5) == 0)
+ i = 1;
+ freeenv(model);
+
+ return (i);
+}
+
+static void
+eeemon_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+
+ if (device_find_child(parent, "eeemon", -1) != NULL)
+ return;
+
+ if (eeemon_match() == 0)
+ return;
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "eeemon", -1);
+ if (child == NULL)
+ device_printf(parent, "add eeemon child failed\n");
+
+}
+
+static int
+eeemon_probe(device_t dev)
+{
+ if (resource_disabled("eeemon", 0))
+ return (ENXIO);
+
+ if (eeemon_match() == 0) {
+ device_printf(dev, "model not recognized\n");
+ return (ENXIO);
+ }
+ device_set_desc(dev, "Asus Eee PC Hardware Monitor");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+eeemon_attach(device_t dev)
+{
+ struct eeemon_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "voltage", CTLTYPE_INT | CTLFLAG_RW,
+ sc, EEEMON_VOLT, eeemon_sysctl, "I",
+ "Voltage (V)");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "fan_manual", CTLTYPE_INT | CTLFLAG_RW,
+ sc, EEEMON_FANMANUAL, eeemon_sysctl, "I",
+ "Fan Manual");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "fan_speed", CTLTYPE_INT | CTLFLAG_RW,
+ sc, EEEMON_FANSPEED, eeemon_sysctl, "I",
+ "Fan Speed (%)");
+
+ sc->sc_ich.ich_func = eeemon_intrhook;
+ sc->sc_ich.ich_arg = sc;
+ config_intrhook_establish(&sc->sc_ich);
+
+ return (0);
+}
+
+static int
+eeemon_detach(device_t dev)
+{
+ struct eeemon_softc *sc;
+
+ sc = device_get_softc(dev);
+ sysctl_remove_oid(sc->sc_sctl_cputemp, 1, 0);
+ sysctl_remove_oid(sc->sc_sctl_cpufan, 1, 0);
+
+ return (0);
+}
+
+static void
+eeemon_intrhook(void *arg)
+{
+ device_t nexus, acpi, cpu;
+ struct sysctl_ctx_list *sysctlctx;
+ struct eeemon_softc *sc;
+
+ sc = arg;
+
+ /*
+ * dev.cpu.0.temperature and dev.cpu.0.fan
+ */
+ nexus = device_find_child(root_bus, "nexus", 0);
+ acpi = device_find_child(nexus, "acpi", 0);
+ cpu = device_find_child(acpi, "cpu", 0);
+ if (cpu) {
+ sysctlctx = device_get_sysctl_ctx(cpu);
+ sc->sc_sctl_cputemp = SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
+ OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
+ sc, EEEMON_TEMP, eeemon_sysctl, "I",
+ "CPU temperature (degC)");
+ sc->sc_sctl_cpufan = SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
+ OID_AUTO, "fan", CTLTYPE_INT | CTLFLAG_RD,
+ sc, EEEMON_FAN, eeemon_sysctl, "I",
+ "CPU Fan speed (RPM)");
+ }
+ config_intrhook_disestablish(&sc->sc_ich);
+}
+
+static int
+eeemon_readbyte(uint16_t addr)
+{
+ int d;
+
+ outb(EEEMON_ADDRH, (addr & 0xff00) >> 8);
+ outb(EEEMON_ADDRL, addr & 0x00ff);
+ d = inb(EEEMON_DATA);
+
+ return (d);
+}
+
+static void
+eeemon_writebyte(uint16_t addr, uint8_t byte)
+{
+ outb(EEEMON_ADDRH, (addr & 0xff00) >> 8);
+ outb(EEEMON_ADDRL, addr & 0x00ff);
+ outb(EEEMON_DATA, byte);
+}
+
+static int
+eeemon_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ int value;
+ unsigned short port;
+ unsigned char mask;
+ int pin;
+ int error;
+
+ switch (arg2) {
+ case EEEMON_TEMP:
+ value = eeemon_readbyte(EEEMON_TEMPVAL);
+ break;
+ case EEEMON_FAN:
+ value = (eeemon_readbyte(EEEMON_FANHVAL) << 8)
+ | eeemon_readbyte(EEEMON_FANLVAL);
+ break;
+ case EEEMON_FANMANUAL:
+ value = (eeemon_readbyte(EEEMON_FANMANUALVAL) & 0x02) ? 1 : 0;
+ break;
+ case EEEMON_FANSPEED:
+ value = eeemon_readbyte(EEEMON_FANSPEEDVAL);
+ break;
+ case EEEMON_VOLT:
+ pin = 0x66;
+ port = 0xfc20 + ((pin >> 3) & 0x1f);
+ mask = 1 << (pin & 0x07);
+ value = (eeemon_readbyte(port) & mask) ? 1 : 0;
+ }
+
+
+ error = sysctl_handle_int(oidp, &value, 0, req);
+ if (error || !req->newptr)
+ return (error);
+
+ switch (arg2) {
+ case EEEMON_FANSPEED:
+ if (value > 100 || value < 0)
+ return (EINVAL);
+ eeemon_writebyte(EEEMON_FANSPEEDVAL, value);
+ break;
+ case EEEMON_FANMANUAL:
+ if (value > 1 || value < 0)
+ return (EINVAL);
+ if (value) {
+ // SF25=1: Prevent the EC from controlling the fan.
+ eeemon_writebyte(EEEMON_FANMANUALVAL, eeemon_readbyte(EEEMON_FANMANUALVAL) | 0x02);
+ } else
+ // SF25=0: Allow the EC to control the fan.
+ eeemon_writebyte(EEEMON_FANMANUALVAL, eeemon_readbyte(EEEMON_FANMANUALVAL) & ~0x02);
+ break;
+ case EEEMON_VOLT:
+ if (value > 1 || value < 0)
+ return (EINVAL);
+ pin = 0x66;
+ port = 0xfc20 + ((pin >> 3) & 0x1f);
+ mask = 1 << (pin & 0x07);
+ if (value) {
+ eeemon_writebyte(port, eeemon_readbyte(port) | mask);
+ } else
+ eeemon_writebyte(port, eeemon_readbyte(port) & ~mask);
+ }
+
+ return (0);
+}
Added: user/rpaulo/eeemon/eeemonreg.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ user/rpaulo/eeemon/eeemonreg.h Fri Oct 10 17:53:26 2008 (r183751)
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2008 Rui Paulo <rpaulo at FreeBSD.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.
+ * 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 THE AUTHOR ``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 THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+
+/*
+ * Port addresses.
+ */
+#define EEEMON_ADDRH 0x381
+#define EEEMON_ADDRL 0x382
+#define EEEMON_DATA 0x383
+
+/*
+ * Values writable to the EC port.
+ */
+
+#define EEEMON_TEMPVAL 0xf451 /* Temperature of CPU (C) */
+#define EEEMON_FANSPEEDVAL 0xf463 /* Fan PWM duty cycle (%) */
+#define EEEMON_FANHVAL 0xf466 /* High byte of fan speed (RPM) */
+#define EEEMON_FANLVAL 0xf467 /* Low byte of fan speed (RPM) */
+#define EEEMON_FANMANUALVAL 0xf4d3 /* Flag byte containing SF25 (FANctrl) */
More information about the svn-src-user
mailing list