summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-09-21 01:10:25 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-09-21 01:10:25 +0000
commite8c4433c035f8e08f75ecc8674de407632657270 (patch)
tree972f0b7a54292a1ede6e5c248fde7cf58f5bf9db
parentaec49b06efd518437143ea082ebc3444b205f905 (diff)
Add support for newer asus boards that use a different method to poll
and enumerate the sensors. When available aibs is using the RTMP, RVLT, and RFAN nodes else in new mode GGRP, GITM, and SITM are used. Tested by me and japser@ on old HW and me and Mattieu Baptiste on new HW. OK deraadt@
-rw-r--r--sys/dev/acpi/atk0110.c484
1 files changed, 324 insertions, 160 deletions
diff --git a/sys/dev/acpi/atk0110.c b/sys/dev/acpi/atk0110.c
index 734535ba905..2e33d6896a7 100644
--- a/sys/dev/acpi/atk0110.c
+++ b/sys/dev/acpi/atk0110.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atk0110.c,v 1.5 2010/09/19 22:46:16 deraadt Exp $ */
+/* $OpenBSD: atk0110.c,v 1.6 2010/09/21 01:10:24 claudio Exp $ */
/*
* Copyright (c) 2009 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
@@ -40,6 +40,19 @@
* -- cnst.su.
*/
+#define ATK_ID_MUX_HWMON 0x00000006
+
+#define ATK_CLASS(x) (((x) >> 24) & 0xff)
+#define ATK_CLASS_FREQ_CTL 3
+#define ATK_CLASS_FAN_CTL 4
+#define ATK_CLASS_HWMON 6
+#define ATK_CLASS_MGMT 17
+
+#define ATK_TYPE(x) (((x) >> 16) & 0xff)
+#define ATK_TYPE_VOLT 2
+#define ATK_TYPE_TEMP 3
+#define ATK_TYPE_FAN 4
+
#define AIBS_MORE_SENSORS
/* #define AIBS_VERBOSE */
@@ -48,6 +61,7 @@ struct aibs_sensor {
int64_t i;
int64_t l;
int64_t h;
+ SIMPLEQ_ENTRY(aibs_sensor) entry;
};
struct aibs_softc {
@@ -56,13 +70,32 @@ struct aibs_softc {
struct acpi_softc *sc_acpi;
struct aml_node *sc_devnode;
- struct aibs_sensor *sc_asens_volt;
- struct aibs_sensor *sc_asens_temp;
- struct aibs_sensor *sc_asens_fan;
+ struct aml_node *sc_ggrpnode;
+ struct aml_node *sc_gitmnode;
+ struct aml_node *sc_sitmnode;
+ struct aml_node *sc_rtmpnode;
+ struct aml_node *sc_rvltnode;
+ struct aml_node *sc_rfannode;
+ SIMPLEQ_HEAD(, aibs_sensor) sc_sensorlist;
struct ksensordev sc_sensordev;
+
+ int sc_mode; /* 1 = new, 0 = old */
+};
+
+/* Command buffer used for GITM and SITM methods */
+struct aibs_cmd_buffer {
+ u_int32_t id;
+ u_int32_t param1;
+ u_int32_t param2;
};
+/* Return buffer used by the GITM and SITM mehtods */
+struct aibs_ret_buffer {
+ u_int32_t flags;
+ u_int32_t value;
+ /* there is more stuff that is unknown */
+};
int aibs_match(struct device *, void *, void *);
void aibs_attach(struct device *, struct device *, void *);
@@ -70,7 +103,14 @@ int aibs_notify(struct aml_node *, int, void *);
void aibs_refresh(void *);
void aibs_attach_sif(struct aibs_softc *, enum sensor_type);
-void aibs_refresh_r(struct aibs_softc *, enum sensor_type);
+void aibs_attach_new(struct aibs_softc *);
+void aibs_add_sensor(struct aibs_softc *, char *);
+void aibs_refresh_r(struct aibs_softc *, struct aibs_sensor *);
+int aibs_getvalue(struct aibs_softc *, int64_t, int64_t *);
+int aibs_getpack(struct aibs_softc *, struct aml_node *, int64_t,
+ struct aml_value *);
+void aibs_probe(struct aibs_softc *);
+int aibs_find_cb(struct aml_node *, void *);
struct cfattach aibs_ca = {
@@ -104,14 +144,20 @@ aibs_attach(struct device *parent, struct device *self, void *aux)
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_devnode = aa->aaa_node;
- printf("\n");
-
strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
sizeof(sc->sc_sensordev.xname));
+ SIMPLEQ_INIT(&sc->sc_sensorlist);
- aibs_attach_sif(sc, SENSOR_TEMP);
- aibs_attach_sif(sc, SENSOR_FANRPM);
- aibs_attach_sif(sc, SENSOR_VOLTS_DC);
+ aibs_probe(sc);
+ printf("\n");
+
+ if (sc->sc_mode)
+ aibs_attach_new(sc);
+ else {
+ aibs_attach_sif(sc, SENSOR_TEMP);
+ aibs_attach_sif(sc, SENSOR_FANRPM);
+ aibs_attach_sif(sc, SENSOR_VOLTS_DC);
+ }
if (sc->sc_sensordev.sensors_count == 0) {
printf("%s: no sensors found\n", DEVNAME(sc));
@@ -131,7 +177,6 @@ aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
struct aml_value **v;
int i, n;
char name[] = "?SIF";
- struct aibs_sensor *as;
switch (st) {
case SENSOR_TEMP:
@@ -152,13 +197,11 @@ aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
aml_freevalue(&res);
return;
}
-
if (res.type != AML_OBJTYPE_PACKAGE) {
printf("%s: %s: not a package\n", DEVNAME(sc), name);
aml_freevalue(&res);
return;
}
-
v = res.v_package;
if (v[0]->type != AML_OBJTYPE_INTEGER) {
printf("%s: %s[0]: invalid type\n", DEVNAME(sc), name);
@@ -186,195 +229,316 @@ aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
return;
}
- as = malloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO);
- if (as == NULL) {
- printf("%s: %s: malloc fail\n", DEVNAME(sc), name);
- aml_freevalue(&res);
- return;
- }
-
- switch (st) {
- case SENSOR_TEMP:
- sc->sc_asens_temp = as;
- break;
- case SENSOR_FANRPM:
- sc->sc_asens_fan = as;
- break;
- case SENSOR_VOLTS_DC:
- sc->sc_asens_volt = as;
- break;
- default:
- /* NOTREACHED */
- return;
- }
-
for (i = 0, v++; i < n; i++, v++) {
- struct aml_value ri;
-
if(v[0]->type != AML_OBJTYPE_STRING) {
printf("%s: %s: %i: not a string: %i type\n",
DEVNAME(sc), name, i, v[0]->type);
continue;
}
- if (aml_evalname(sc->sc_acpi, sc->sc_devnode, v[0]->v_string,
- 0, NULL, &ri)) {
- printf("%s: %s: %i: %s not found\n",
- DEVNAME(sc), name, i, v[0]->v_string);
- aml_freevalue(&ri);
- continue;
- }
- if (ri.type != AML_OBJTYPE_PACKAGE) {
- printf("%s: %s: %i: %s: not a package\n",
- DEVNAME(sc), name, i, v[0]->v_string);
- aml_freevalue(&ri);
- continue;
- }
- if (ri.length != 5 ||
- ri.v_package[0]->type != AML_OBJTYPE_INTEGER ||
- ri.v_package[1]->type != AML_OBJTYPE_STRING ||
- ri.v_package[2]->type != AML_OBJTYPE_INTEGER ||
- ri.v_package[3]->type != AML_OBJTYPE_INTEGER ||
- ri.v_package[4]->type != AML_OBJTYPE_INTEGER) {
- printf("%s: %s: %i: %s: invalid package\n",
- DEVNAME(sc), name, i, v[0]->v_string);
- aml_freevalue(&ri);
+ aibs_add_sensor(sc, v[0]->v_string);
+ }
+
+ aml_freevalue(&res);
+}
+
+void
+aibs_attach_new(struct aibs_softc *sc)
+{
+ struct aml_value res;
+ int i;
+
+ if (aibs_getpack(sc, sc->sc_ggrpnode, ATK_ID_MUX_HWMON, &res)) {
+ printf("%s: GGRP: sensor enumeration failed", DEVNAME(sc));
+ return;
+ }
+
+ for (i = 0; i < res.length; i++) {
+ struct aml_value *r;
+ r = res.v_package[i];
+ if (r->type != AML_OBJTYPE_STRING) {
+ printf("%s: %s: %i: not a string (type %i)\n",
+ DEVNAME(sc), "GGRP", i, r->type);
continue;
}
- as[i].i = ri.v_package[0]->v_integer;
- strlcpy(as[i].s.desc, ri.v_package[1]->v_string,
- sizeof(as[i].s.desc));
- as[i].l = ri.v_package[2]->v_integer;
- as[i].h = ri.v_package[3]->v_integer;
- as[i].s.type = st;
-#ifdef AIBS_VERBOSE
- printf("%s: %s %2i: %4s: "
- "0x%08llx %20s %5lli / %5lli 0x%llx\n",
- DEVNAME(sc), name, i, v[0]->v_string,
- as[i].i, as[i].s.desc, as[i].l, as[i].h,
- ri.v_package[4]->v_integer);
-#endif
- sensor_attach(&sc->sc_sensordev, &as[i].s);
+ aibs_add_sensor(sc, r->v_string);
+ }
+ aml_freevalue(&res);
+}
+
+void
+aibs_add_sensor(struct aibs_softc *sc, char *name)
+{
+ struct aml_value ri;
+ struct aibs_sensor *as;
+ int len, lim1, lim2, ena;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name,
+ 0, NULL, &ri)) {
+ printf("%s: aibs_add_sensor: %s not found\n",
+ DEVNAME(sc), name, name);
+ aml_freevalue(&ri);
+ return;
+ }
+ if (ri.type != AML_OBJTYPE_PACKAGE) {
+ printf("%s: aibs_add_sensor: %s: not a package\n",
+ DEVNAME(sc), name);
aml_freevalue(&ri);
+ return;
+ }
+ if (sc->sc_mode) {
+ len = 7;
+ lim1 = 4;
+ lim2 = 5;
+ ena = 6;
+ } else {
+ len = 5;
+ lim1 = 2;
+ lim2 = 3;
+ ena = 4;
}
- aml_freevalue(&res);
+ if (ri.length != len ||
+ ri.v_package[0]->type != AML_OBJTYPE_INTEGER ||
+ ri.v_package[1]->type != AML_OBJTYPE_STRING ||
+ ri.v_package[lim1]->type != AML_OBJTYPE_INTEGER ||
+ ri.v_package[lim2]->type != AML_OBJTYPE_INTEGER ||
+ ri.v_package[ena]->type != AML_OBJTYPE_INTEGER) {
+ printf("%s: aibs_add_sensor: %s: invalid package\n",
+ DEVNAME(sc), name);
+ aml_freevalue(&ri);
+ return;
+ }
+ as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (!as) {
+ printf("%s: aibs_add_sensor: %s: failed to allocate sensor\n",
+ DEVNAME(sc), name);
+ aml_freevalue(&ri);
+ return;
+ }
+ as->i = ri.v_package[0]->v_integer;
+ switch (ATK_TYPE(as->i)) {
+ case ATK_TYPE_VOLT:
+ as->s.type = SENSOR_VOLTS_DC;
+ break;
+ case ATK_TYPE_TEMP:
+ as->s.type = SENSOR_TEMP;
+ break;
+ case ATK_TYPE_FAN:
+ as->s.type = SENSOR_FANRPM;
+ break;
+ default:
+ printf("%s: aibs_add_sensor: %s: unknown sensor type %llx\n",
+ DEVNAME(sc), name, ri.v_package[0]->v_integer);
+ aml_freevalue(&ri);
+ free(as, M_DEVBUF);
+ return;
+ }
+ strlcpy(as->s.desc, ri.v_package[1]->v_string,
+ sizeof(as->s.desc));
+ as->l = ri.v_package[lim1]->v_integer;
+ if (sc->sc_mode)
+ /* the second limit is a actually a range */
+ as->h = as->l + ri.v_package[lim2]->v_integer;
+ else
+ as->h = ri.v_package[lim2]->v_integer;
+#ifdef AIBS_VERBOSE
+ printf("%s: %4s: %s 0x%08llx %5lli / %5lli 0x%llx\n",
+ DEVNAME(sc), name, as->s.desc, as->i, as->l, as->h,
+ ri.v_package[ena]->v_integer);
+#endif
+ SIMPLEQ_INSERT_TAIL(&sc->sc_sensorlist, as, entry);
+ sensor_attach(&sc->sc_sensordev, &as->s);
+ aml_freevalue(&ri);
return;
}
void
aibs_refresh(void *arg)
{
- struct aibs_softc *sc = arg;
+ struct aibs_softc *sc = arg;
+ struct aibs_sensor *as;
- aibs_refresh_r(sc, SENSOR_TEMP);
- aibs_refresh_r(sc, SENSOR_FANRPM);
- aibs_refresh_r(sc, SENSOR_VOLTS_DC);
+ SIMPLEQ_FOREACH(as, &sc->sc_sensorlist, entry)
+ aibs_refresh_r(sc, as);
}
void
-aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st)
+aibs_refresh_r(struct aibs_softc *sc, struct aibs_sensor *as)
{
- struct aml_node *node;
- int i, n = sc->sc_sensordev.maxnumt[st];
- char *name;
- struct aibs_sensor *as;
+ struct ksensor *s = &as->s;
+ int64_t v;
+ const int64_t l = as->l, h = as->h;
- switch (st) {
+ if (aibs_getvalue(sc, as->i, &v)) {
+ s->flags |= SENSOR_FINVALID;
+ return;
+ }
+ switch (s->type) {
case SENSOR_TEMP:
- name = "RTMP";
- as = sc->sc_asens_temp;
+ s->value = v * 100 * 1000 + 273150000;
+ if (v == 0) {
+ s->status = SENSOR_S_UNKNOWN;
+ s->flags |= SENSOR_FINVALID;
+ } else {
+ if (v > h)
+ s->status = SENSOR_S_CRIT;
+ else if (v > l)
+ s->status = SENSOR_S_WARN;
+ else
+ s->status = SENSOR_S_OK;
+ s->flags &= ~SENSOR_FINVALID;
+ }
break;
case SENSOR_FANRPM:
- name = "RFAN";
- as = sc->sc_asens_fan;
+ s->value = v;
+ /* some boards have strange limits for fans */
+ if ((l != 0 && l < v && v < h) ||
+ (l == 0 && v > h))
+ s->status = SENSOR_S_OK;
+ else
+ s->status = SENSOR_S_WARN;
+ s->flags &= ~SENSOR_FINVALID;
break;
case SENSOR_VOLTS_DC:
- name = "RVLT";
- as = sc->sc_asens_volt;
+ s->value = v * 1000;
+ if (l < v && v < h)
+ s->status = SENSOR_S_OK;
+ else
+ s->status = SENSOR_S_WARN;
+ s->flags &= ~SENSOR_FINVALID;
break;
default:
- return;
+ /* NOTREACHED */
+ break;
}
+}
- if (as == NULL)
- return;
+int
+aibs_getvalue(struct aibs_softc *sc, int64_t i, int64_t *v)
+{
+ struct aml_node *n = sc->sc_gitmnode;
+ struct aml_value req, res;
+ struct aibs_cmd_buffer cmd;
+ struct aibs_ret_buffer ret;
+ enum aml_objecttype type;
+
+ if (sc->sc_mode) {
+ cmd.id = i;
+ cmd.param1 = 0;
+ cmd.param2 = 0;
+ type = req.type = AML_OBJTYPE_BUFFER;
+ req.v_buffer = (uint8_t *)&cmd;
+ req.length = sizeof(cmd);
+ } else {
+ switch (ATK_TYPE(i)) {
+ case ATK_TYPE_TEMP:
+ n = sc->sc_rtmpnode;
+ break;
+ case ATK_TYPE_FAN:
+ n = sc->sc_rfannode;
+ break;
+ case ATK_TYPE_VOLT:
+ n = sc->sc_rvltnode;
+ break;
+ default:
+ return (-1);
+ }
+ type = req.type = AML_OBJTYPE_INTEGER;
+ req.v_integer = i;
+ }
- node = aml_searchname(sc->sc_devnode, name);
- if (node == NULL || node->value == NULL ||
- node->value->type != AML_OBJTYPE_METHOD) {
- dprintf("%s: %s: method node not found\n",
- DEVNAME(sc), name);
- for (i = 0; i < n; i++)
- as[i].s.flags |= SENSOR_FINVALID;
- return;
+ if (aml_evalnode(sc->sc_acpi, n, 1, &req, &res)) {
+ dprintf("%s: %s: %i: evaluation failed\n",
+ DEVNAME(sc), n->name, i);
+ aml_freevalue(&res);
+ return (-1);
+ }
+ if (res.type != type) {
+ dprintf("%s: %s: %i: not an integer: type %i\n",
+ DEVNAME(sc), n->name, i, res.type);
+ aml_freevalue(&res);
+ return (-1);
}
- for (i = 0; i < n; i++) {
- struct aml_value req, res;
- int64_t v;
- struct ksensor *s = &as[i].s;
- const int64_t l = as[i].l, h = as[i].h;
-
- req.type = AML_OBJTYPE_INTEGER;
- req.v_integer = as[i].i;
- if (aml_evalnode(sc->sc_acpi, node, 1, &req, &res)) {
- dprintf("%s: %s: %i: evaluation failed\n",
- DEVNAME(sc), name, i);
+ if (sc->sc_mode) {
+ if (res.length < sizeof(ret)) {
+ dprintf("%s: %s: %i: result buffer too small\n",
+ DEVNAME(sc), n->name, i);
aml_freevalue(&res);
- s->flags |= SENSOR_FINVALID;
- continue;
+ return (-1);
}
- if (res.type != AML_OBJTYPE_INTEGER) {
- dprintf("%s: %s: %i: not an integer: type %i\n",
- DEVNAME(sc), name, i, res.type);
+ bcopy(res.v_buffer, &ret, sizeof(ret));
+ if (ret.flags == 0) {
+ dprintf("%s: %s: %i: bad flags in result\n",
+ DEVNAME(sc), n->name, i);
aml_freevalue(&res);
- s->flags |= SENSOR_FINVALID;
- continue;
+ return (-1);
}
- v = res.v_integer;
- aml_freevalue(&res);
+ *v = ret.value;
+ } else {
+ *v = res.v_integer;
+ }
+ aml_freevalue(&res);
- switch (st) {
- case SENSOR_TEMP:
- s->value = v * 100 * 1000 + 273150000;
- if (v == 0) {
- s->status = SENSOR_S_UNKNOWN;
- s->flags |= SENSOR_FINVALID;
- } else {
- if (v > h)
- s->status = SENSOR_S_CRIT;
- else if (v > l)
- s->status = SENSOR_S_WARN;
- else
- s->status = SENSOR_S_OK;
- s->flags &= ~SENSOR_FINVALID;
- }
- break;
- case SENSOR_FANRPM:
- s->value = v;
- /* some boards have strange limits for fans */
- if ((l != 0 && l < v && v < h) ||
- (l == 0 && v > h))
- s->status = SENSOR_S_OK;
- else
- s->status = SENSOR_S_WARN;
- s->flags &= ~SENSOR_FINVALID;
- break;
- case SENSOR_VOLTS_DC:
- s->value = v * 1000;
- if (l < v && v < h)
- s->status = SENSOR_S_OK;
- else
- s->status = SENSOR_S_WARN;
- s->flags &= ~SENSOR_FINVALID;
- break;
- default:
- /* NOTREACHED */
- break;
- }
+ return (0);
+}
+
+int
+aibs_getpack(struct aibs_softc *sc, struct aml_node *n, int64_t i,
+ struct aml_value *res)
+{
+ struct aml_value req;
+
+ req.type = AML_OBJTYPE_INTEGER;
+ req.v_integer = i;
+
+ if (aml_evalnode(sc->sc_acpi, n, 1, &req, res)) {
+ dprintf("%s: %s: %i: evaluation failed\n",
+ DEVNAME(sc), n->name, i);
+ aml_freevalue(res);
+ return (-1);
+ }
+ if (res->type != AML_OBJTYPE_PACKAGE) {
+ dprintf("%s: %s: %i: not a package: type %i\n",
+ DEVNAME(sc), n->name, i, res->type);
+ aml_freevalue(res);
+ return (-1);
}
- return;
+ return (0);
+}
+
+void
+aibs_probe(struct aibs_softc *sc)
+{
+ /*
+ * Old mode uses TSIF, VSIF, and FSIF to enumerate sensors and
+ * RTMP, RVLT, and RFAN are used to get the values.
+ * New mode uses GGRP for enumeration and GITM and SITM as accessor.
+ * If the new methods are available use them else default to old mode.
+ */
+ printf(":");
+ aml_find_node(sc->sc_devnode, "RTMP", aibs_find_cb, &sc->sc_rtmpnode);
+ aml_find_node(sc->sc_devnode, "RVLT", aibs_find_cb, &sc->sc_rvltnode);
+ aml_find_node(sc->sc_devnode, "RFAN", aibs_find_cb, &sc->sc_rfannode);
+
+ aml_find_node(sc->sc_devnode, "GGRP", aibs_find_cb, &sc->sc_ggrpnode);
+ aml_find_node(sc->sc_devnode, "GITM", aibs_find_cb, &sc->sc_gitmnode);
+ aml_find_node(sc->sc_devnode, "SITM", aibs_find_cb, &sc->sc_sitmnode);
+
+ if (sc->sc_ggrpnode && sc->sc_gitmnode && sc->sc_sitmnode &&
+ !sc->sc_rtmpnode && !sc->sc_rvltnode && !sc->sc_rfannode)
+ sc->sc_mode = 1;
+}
+
+int
+aibs_find_cb(struct aml_node *node, void *arg)
+{
+ struct aml_node **np = arg;
+
+ printf(" %s", node->name);
+ *np = node;
+ return (1);
}
int