Imported envsys 2, a brief description of the new features:

(Part 1: API)

* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
  and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
  sysmon_power(9) and powerd(8), that means there is no 32 bytes event
  size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.

Tested by:

blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
This commit is contained in:
xtraeme 2007-07-01 07:36:39 +00:00
parent be8757ef61
commit bf4558f8cf
9 changed files with 2451 additions and 367 deletions

View File

@ -1,20 +1,21 @@
# $NetBSD: files.sysmon,v 1.5 2005/12/11 12:23:56 christos Exp $
define sysmon_envsys
file dev/sysmon/sysmon_envsys.c sysmon_envsys needs-flag
define sysmon_wdog
file dev/sysmon/sysmon_wdog.c sysmon_wdog needs-flag
define sysmon_power
file dev/sysmon/sysmon_power.c sysmon_power needs-flag
file dev/sysmon/sysmon.c sysmon_envsys | sysmon_wdog |
sysmon_power
# $NetBSD: files.sysmon,v 1.6 2007/07/01 07:36:43 xtraeme Exp $
define sysmon_taskq
file dev/sysmon/sysmon_taskq.c sysmon_taskq
define sysmon_power
file dev/sysmon/sysmon_power.c sysmon_power needs-flag
define sysmon_envsys: sysmon_power, sysmon_taskq
file dev/sysmon/sysmon_envsys.c sysmon_envsys needs-flag
file dev/sysmon/sysmon_envsys_events.c sysmon_envsys
define sysmon_wdog
file dev/sysmon/sysmon_wdog.c sysmon_wdog needs-flag
file dev/sysmon/sysmon.c sysmon_envsys | sysmon_envsys_events |
sysmon_wdog | sysmon_power
defpseudo swwdog: sysmon_wdog
file dev/sysmon/swwdog.c swwdog needs-count

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,577 @@
/* $NetBSD: sysmon_envsys_events.c,v 1.1 2007/07/01 07:36:52 xtraeme Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juan Romero Pardines.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Juan Romero Pardines
* for the NetBSD Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* sysmon_envsys(9) events framework.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.1 2007/07/01 07:36:52 xtraeme Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/mutex.h>
#include <sys/kmem.h>
#include <sys/callout.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/sysmon/sysmon_envsysvar.h>
struct sme_sensor_state {
int type;
const char *desc;
};
static const struct sme_sensor_state sme_sensor_drive_state[] = {
{ ENVSYS_DRIVE_EMPTY, "drive state is unknown" },
{ ENVSYS_DRIVE_READY, "drive is ready" },
{ ENVSYS_DRIVE_POWERUP, "drive is powering up" },
{ ENVSYS_DRIVE_ONLINE, "drive is online" },
{ ENVSYS_DRIVE_IDLE, "drive is idle" },
{ ENVSYS_DRIVE_ACTIVE, "drive is active" },
{ ENVSYS_DRIVE_REBUILD, "drive is rebuilding" },
{ ENVSYS_DRIVE_POWERDOWN, "drive is powering down" },
{ ENVSYS_DRIVE_FAIL, "drive failed" },
{ ENVSYS_DRIVE_PFAIL, "drive degraded" },
{ -1, "unknown" }
};
static struct workqueue *seewq;
static struct callout seeco;
static bool sme_events_initialized = false;
kmutex_t sme_mtx, sme_event_mtx, sme_event_init_mtx;
/*
* sme_event_register:
*
* + Registers a sysmon envsys event.
* + Creates a new sysmon envsys event.
*/
int
sme_event_register(sme_event_t *see)
{
sme_event_t *lsee;
struct penvsys_state *pes_old, *pes_new;
int error = 0;
KASSERT(see != NULL);
pes_new = &see->pes;
mutex_enter(&sme_event_mtx);
/*
* Ensure that we don't add events for the same sensor
* and with the same type.
*/
LIST_FOREACH(lsee, &sme_events_list, see_list) {
pes_old = &lsee->pes;
if (strcmp(pes_old->pes_sensname,
pes_new->pes_sensname) == 0) {
if (lsee->type == see->type) {
DPRINTF(("%s: dev=%s sensor=%s type=%d "
"(already exists)\n", __func__,
see->pes.pes_dvname,
see->pes.pes_sensname, see->type));
error = EEXIST;
goto out;
}
}
}
DPRINTF(("%s: dev=%s sensor=%s snum=%d type=%d "
"critval=%" PRIu32 "\n", __func__,
see->pes.pes_dvname, see->pes.pes_sensname,
see->snum, see->type, see->critval));
LIST_INSERT_HEAD(&sme_events_list, see, see_list);
/*
* Initialize the events framework if it wasn't initialized
* before.
*/
mutex_enter(&sme_event_init_mtx);
if (sme_events_initialized == false)
error = sme_events_init();
mutex_exit(&sme_event_init_mtx);
out:
mutex_exit(&sme_event_mtx);
return error;
}
/*
* sme_event_unregister:
*
* + Unregisters a sysmon envsys event.
*/
int
sme_event_unregister(const char *sensor, int type)
{
sme_event_t *see;
bool found = false;
KASSERT(sensor != NULL);
mutex_enter(&sme_event_mtx);
LIST_FOREACH(see, &sme_events_list, see_list) {
if (strcmp(see->pes.pes_sensname, sensor) == 0) {
if (see->type == type) {
found = true;
break;
}
}
}
if (!found) {
mutex_exit(&sme_event_mtx);
return EINVAL;
}
DPRINTF(("%s: removing dev=%s sensor=%s type=%d\n",
__func__, see->pes.pes_dvname, sensor, type));
LIST_REMOVE(see, see_list);
/*
* So the events list is empty, we'll do the following:
*
* - stop the callout.
* - destroy the workqueue.
*/
if (LIST_EMPTY(&sme_events_list)) {
mutex_exit(&sme_event_mtx);
mutex_enter(&sme_event_init_mtx);
callout_stop(&seeco);
workqueue_destroy(seewq);
sme_events_initialized = false;
DPRINTF(("%s: events framework destroyed\n", __func__));
mutex_exit(&sme_event_init_mtx);
goto out;
}
mutex_exit(&sme_event_mtx);
kmem_free(see, sizeof(*see));
out:
return 0;
}
/*
* sme_event_drvadd:
*
* + Adds a new sysmon envsys event for a driver if a sensor
* has set any accepted monitoring flag.
*/
void
sme_event_drvadd(void *arg)
{
sme_event_drv_t *sed_t = arg;
KASSERT(sed_t != NULL);
#define SEE_REGEVENT(a, b, c) \
do { \
if (sed_t->edata->flags & (a)) { \
char str[32] = "monitoring-state-"; \
\
if (sme_event_add(sed_t->sdict, \
sed_t->edata, \
sed_t->sme->sme_name, \
NULL, \
0, \
(b), \
sed_t->powertype)) \
printf("%s: failed to add event (%s)\n", \
__func__, (c)); \
mutex_enter(&sme_mtx); \
(void)strlcat(str, (c), sizeof(str)); \
prop_dictionary_set_bool(sed_t->sdict, str, true); \
mutex_exit(&sme_mtx); \
} \
} while (/* CONSTCOND */ 0)
SEE_REGEVENT(ENVSYS_FMONCRITICAL,
PENVSYS_EVENT_CRITICAL,
"critical");
SEE_REGEVENT(ENVSYS_FMONCRITUNDER,
PENVSYS_EVENT_CRITUNDER,
"critunder");
SEE_REGEVENT(ENVSYS_FMONCRITOVER,
PENVSYS_EVENT_CRITOVER,
"critover");
SEE_REGEVENT(ENVSYS_FMONWARNUNDER,
PENVSYS_EVENT_WARNUNDER,
"warnunder");
SEE_REGEVENT(ENVSYS_FMONWARNOVER,
PENVSYS_EVENT_WARNOVER,
"warnover");
SEE_REGEVENT(ENVSYS_FMONDRVSTATE,
PENVSYS_EVENT_DRIVE_STCHANGED,
"drvstchanged");
/* we are done, free memory now */
kmem_free(sed_t, sizeof(*sed_t));
}
/*
* sme_event_add:
*
* + Initializes or updates a sysmon envsys event.
*/
int
sme_event_add(prop_dictionary_t sdict, envsys_data_t *edata,
const char *drvn, const char *objkey,
int32_t critval, int crittype, int powertype)
{
sme_event_t *see = NULL;
prop_object_t obj;
int error = 0;
KASSERT(sdict != NULL || edata != NULL);
/* critical condition set via userland */
if (objkey && critval) {
obj = prop_dictionary_get(sdict, objkey);
if (obj != NULL) {
/*
* object is already in dictionary, update
* the critical value.
*/
mutex_enter(&sme_event_mtx);
LIST_FOREACH(see, &sme_events_list, see_list) {
if (strcmp(edata->desc,
see->pes.pes_sensname) == 0)
if (crittype == see->type)
break;
}
see->critval = critval;
mutex_exit(&sme_event_mtx);
DPRINTF(("%s: event updated\n", __func__));
goto out;
}
}
if (LIST_EMPTY(&sme_events_list))
goto register_event;
/* check if the event is already on the list */
mutex_enter(&sme_event_mtx);
LIST_FOREACH(see, &sme_events_list, see_list) {
if (strcmp(edata->desc, see->pes.pes_sensname) == 0)
if (crittype == see->type) {
mutex_exit(&sme_event_mtx);
error = EEXIST;
goto out;
}
}
mutex_exit(&sme_event_mtx);
/*
* object is not in dictionary, create a new
* sme event and assign required members.
*/
register_event:
see = kmem_zalloc(sizeof(*see), KM_SLEEP);
mutex_enter(&sme_event_mtx);
see->critval = critval;
see->type = crittype;
(void)strlcpy(see->pes.pes_dvname, drvn,
sizeof(see->pes.pes_dvname));
see->pes.pes_type = powertype;
(void)strlcpy(see->pes.pes_sensname, edata->desc,
sizeof(see->pes.pes_sensname));
see->snum = edata->sensor;
mutex_exit(&sme_event_mtx);
if (sme_event_register(see)) {
kmem_free(see, sizeof(*see));
return EINVAL;
}
out:
/* update the object in the dictionary */
if (objkey && critval) {
mutex_enter(&sme_event_mtx);
SENSOR_UPINT32(sdict, objkey, critval);
mutex_exit(&sme_event_mtx);
}
return error;
}
/*
* sme_events_init:
*
* + Initializes the callout and the workqueue to handle
* the sysmon envsys events.
*/
int
sme_events_init(void)
{
int error;
error = workqueue_create(&seewq, "envsysev",
sme_events_worker, NULL, 0, IPL_NONE, 0);
if (error)
goto out;
callout_init(&seeco);
callout_setfunc(&seeco, sme_events_check, NULL);
callout_schedule(&seeco, SME_EVTIMO);
sme_events_initialized = true;
DPRINTF(("%s: events framework initialized\n", __func__));
out:
return error;
}
/*
* sme_events_check:
*
* + Runs the work on each sysmon envsys event in our
* workqueue periodically with callout.
*/
void
sme_events_check(void *arg)
{
sme_event_t *see;
LIST_FOREACH(see, &sme_events_list, see_list) {
DPRINTF(("%s: dev=%s sensor=%s type=%d\n",
__func__,
see->pes.pes_dvname,
see->pes.pes_sensname,
see->type));
workqueue_enqueue(seewq, &see->see_wk);
}
callout_schedule(&seeco, SME_EVTIMO);
}
/*
* sme_events_worker:
*
* + workqueue thread that checks if there's a critical condition
* and sends an event if the condition was triggered.
*/
void
sme_events_worker(struct work *wk, void *arg)
{
const struct sme_sensor_state *esds = sme_sensor_drive_state;
sme_event_t *see = (void *)wk;
struct sysmon_envsys *sme;
envsys_data_t *edata;
int d, i, error = 0;
KASSERT(wk == &see->see_wk);
/* XXX: NOT YET mutex_enter(&sme_event_mtx); */
/*
* We have to find the sme device by looking
* at the power envsys device name.
*/
LIST_FOREACH(sme, &sysmon_envsys_list, sme_list)
if (strcmp(sme->sme_name, see->pes.pes_dvname) == 0)
break;
KASSERT(sme != NULL);
/* get the sensor number in the sme event */
d = see->snum;
edata = &sme->sme_sensor_data[d];
/*
* refresh the sensor that was marked with a critical
* event.
*/
if ((sme->sme_flags & SME_DISABLE_GTREDATA) == 0) {
error = (*sme->sme_gtredata)(sme, edata);
if (error) {
mutex_exit(&sme_event_mtx);
return;
}
}
DPRINTF(("%s: desc=%s sensor=%d units=%d value_cur=%d\n",
__func__, edata->desc, edata->sensor,
edata->units, edata->value_cur));
#define SME_SENDNORMALEVENT() \
do { \
if (see->evsent && edata->state == ENVSYS_SVALID) { \
see->evsent = false; \
sysmon_penvsys_event(&see->pes, PENVSYS_EVENT_NORMAL); \
} \
} while (/* CONSTCOND */ 0)
switch (see->type) {
/* handle a critical limit event */
case PENVSYS_EVENT_CRITICAL:
SME_SENDNORMALEVENT();
if (!see->evsent && edata->state == ENVSYS_SCRITICAL) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_CRITICAL);
}
break;
/* handle a critical under limit event */
case PENVSYS_EVENT_CRITUNDER:
SME_SENDNORMALEVENT();
if (!see->evsent && edata->state == ENVSYS_SCRITUNDER) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_CRITUNDER);
}
break;
/* handle a critical over limit event */
case PENVSYS_EVENT_CRITOVER:
SME_SENDNORMALEVENT();
if (!see->evsent && edata->state == ENVSYS_SCRITOVER) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_CRITOVER);
}
break;
/* handle a warning under limit event */
case PENVSYS_EVENT_WARNUNDER:
SME_SENDNORMALEVENT();
if (!see->evsent && edata->state == ENVSYS_SWARNUNDER) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_WARNUNDER);
}
break;
/* handle a warning over limit event */
case PENVSYS_EVENT_WARNOVER:
SME_SENDNORMALEVENT();
if (!see->evsent && edata->state == ENVSYS_SWARNOVER) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_WARNOVER);
}
break;
/* handle an user critical capacity */
case PENVSYS_EVENT_BATT_USERCAP:
if (see->evsent && edata->value_cur > see->critval) {
see->evsent = false;
sysmon_penvsys_event(&see->pes, PENVSYS_EVENT_NORMAL);
}
if (!see->evsent && edata->value_cur < see->critval) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_BATT_USERCAP);
}
break;
/* handle a max critical event */
case PENVSYS_EVENT_USER_CRITMAX:
if (see->evsent && edata->value_cur < see->critval) {
see->evsent = false;
sysmon_penvsys_event(&see->pes, PENVSYS_EVENT_NORMAL);
}
if (!see->evsent && edata->value_cur > see->critval) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_USER_CRITMAX);
}
break;
/* handle a min critical event */
case PENVSYS_EVENT_USER_CRITMIN:
if (see->evsent && edata->value_cur > see->critval) {
see->evsent = false;
sysmon_penvsys_event(&see->pes, PENVSYS_EVENT_NORMAL);
}
if (!see->evsent && edata->value_cur < see->critval) {
see->evsent = true;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_USER_CRITMIN);
}
break;
/* handle a drive state change event */
case PENVSYS_EVENT_DRIVE_STCHANGED:
/* the state has not been changed, just ignore the event */
if (edata->value_cur == see->evsent)
break;
for (i = 0; esds[i].type != -1; i++)
if (esds[i].type == edata->value_cur)
break;
/* copy current state description */
(void)strlcpy(see->pes.pes_statedesc, esds[i].desc,
sizeof(see->pes.pes_statedesc));
/* state is ok again... send a normal event */
if (see->evsent && edata->value_cur == ENVSYS_DRIVE_ONLINE) {
see->evsent = false;
sysmon_penvsys_event(&see->pes, PENVSYS_EVENT_NORMAL);
}
/* something bad happened to the drive... send the event */
if (see->evsent || edata->value_cur != ENVSYS_DRIVE_ONLINE) {
/* save current drive state */
see->evsent = edata->value_cur;
sysmon_penvsys_event(&see->pes,
PENVSYS_EVENT_DRIVE_STCHANGED);
}
break;
default:
break;
}
/* XXX: NOT YET mutex_exit(&sme_event_mtx); */
}

View File

@ -0,0 +1,190 @@
/* $NetBSD: sysmon_envsysvar.h,v 1.1 2007/07/01 07:36:56 xtraeme Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juan Romero Pardines.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Juan Romero Pardines
* for the NetBSD Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
#ifndef _DEV_SYSMON_ENVSYSVAR_H_
#define _DEV_SYSMON_ENVSYSVAR_H_
#include <sys/param.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/mutex.h>
#include <sys/workqueue.h>
#include <dev/sysmon/sysmonvar.h>
#include <prop/proplib.h>
#ifdef ENVSYS_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif
#ifdef ENVSYS_OBJECTS_DEBUG
#define DPRINTFOBJ(x) printf x
#else
#define DPRINTFOBJ(x)
#endif
/*
* We run at ENVSYS version 2.
*/
#define SYSMON_ENVSYS_VERSION (2 * 1000)
/* timeout for the callout */
#define SME_EVTIMO (10 * hz) /* 10 seconds */
/* convenience macros to avoid writing same code many times */
#define SENSOR_OBJUPDATED(a, b) \
do { \
DPRINTFOBJ(("%s: obj (%s:%d) updated\n", __func__, (a), (b))); \
} while (/* CONSTCOND */ 0)
#define SENSOR_DICTSETFAILED(a, b) \
do { \
DPRINTF(("%s: dict_set (%s:%d) failed\n", __func__, (a), (b))); \
} while (/* CONSTCOND */ 0)
#define SENSOR_SETTYPE(a, b, c, d) \
do { \
if (!prop_dictionary_set_ ## d((a), (b), (c))) { \
SENSOR_DICTSETFAILED((b), (c)); \
if ((a)) \
prop_object_release((a)); \
goto out; \
} \
} while (/* CONSTCOND */ 0)
#define SENSOR_SINT32(a, b, c) SENSOR_SETTYPE(a, b, c, int32)
#define SENSOR_SUINT32(a, b, c) SENSOR_SETTYPE(a, b, c, uint32)
#define SENSOR_SBOOL(a, b, c) SENSOR_SETTYPE(a, b, c, bool)
#define SENSOR_SSTRING(a, b, c) \
do { \
if (!prop_dictionary_set_cstring_nocopy((a), (b), (c))) { \
DPRINTF(("%s: set_cstring (%s) failed.\n", \
__func__, (c))); \
if ((a)) \
prop_object_release((a)); \
goto out; \
} \
} while (/* CONSTCOND */ 0)
#define SENSOR_UPTYPE(a, b, c, d, e) \
do { \
obj = prop_dictionary_get((a), (b)); \
if (!prop_number_equals_ ## e(obj, (c)) && (c)) { \
if (!prop_dictionary_set_ ## d((a), (b), (c))) { \
SENSOR_DICTSETFAILED((b), (c)); \
return EINVAL; \
} \
SENSOR_OBJUPDATED((b), (c)); \
} \
} while (/* CONSTCOND */ 0)
#define SENSOR_UPINT32(a, b, c) \
SENSOR_UPTYPE(a, b, c, int32, integer)
#define SENSOR_UPUINT32(a, b, c) \
SENSOR_UPTYPE(a, b, c, uint32, unsigned_integer)
#define SENSOR_UPSTRING(a, b, c) \
do { \
obj = prop_dictionary_get((a), (b)); \
if (obj == NULL) { \
SENSOR_SSTRING((a), (b), (c)); \
} else { \
if (!prop_string_equals_cstring((obj), (c))) { \
SENSOR_SSTRING((a), (b), (c)); \
} \
} \
} while (/* CONSTCOND */ 0)
/* struct used by a sysmon envsys event */
typedef struct sme_event {
/* to add works into our workqueue */
union {
struct work u_work;
TAILQ_ENTRY(sme_event) u_q;
} see_u;
#define see_wk see_u.u_work
#define see_q see_u.u_q
LIST_ENTRY(sme_event) see_list;
struct penvsys_state pes; /* our power envsys */
int32_t critval; /* critical value set */
int type; /* type of the event */
int snum; /* sensor number */
int evsent; /* event already sent */
} sme_event_t;
/* struct by a sysmon envsys event set by a driver */
typedef struct sme_event_drv {
struct sysmon_envsys *sme;
prop_dictionary_t sdict;
envsys_data_t *edata;
int powertype;
} sme_event_drv_t;
/* common */
extern kmutex_t sme_mtx; /* mutex for the sysmon envsys devices */
extern kmutex_t sme_event_mtx; /* mutex for the sysmon envsys events */
extern kmutex_t sme_event_init_mtx; /* mutex to initialize/destroy see */
/* linked list for the sysmon envsys devices */
LIST_HEAD(, sysmon_envsys) sysmon_envsys_list;
/* linked list for the sysmon envsys events */
LIST_HEAD(, sme_event) sme_events_list;
/* functions to handle sysmon envsys devices */
int sysmon_envsys_createplist(struct sysmon_envsys *);
int sme_make_dictionary(struct sysmon_envsys *, prop_array_t,
envsys_data_t *);
int sme_update_dictionary(struct sysmon_envsys *);
int sme_userset_dictionary(struct sysmon_envsys *,
prop_dictionary_t, prop_array_t);
/* functions to handle sysmon envsys events */
int sme_event_register(struct sme_event *);
int sme_event_unregister(const char *, int);
void sme_event_drvadd(void *);
int sme_event_add(prop_dictionary_t, envsys_data_t *,
const char *, const char *, int32_t, int, int);
int sme_events_init(void);
void sme_events_check(void *);
void sme_events_worker(struct work *, void *);
#endif /* _DEV_SYSMON_ENVSYSVAR_H_ */

View File

@ -1,4 +1,40 @@
/* $NetBSD: sysmon_power.c,v 1.17 2007/03/04 06:02:45 christos Exp $ */
/* $NetBSD: sysmon_power.c,v 1.18 2007/07/01 07:36:59 xtraeme Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juan Romero Pardines.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Juan Romero Pardines
* for the NetBSD Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -44,41 +80,110 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.17 2007/03/04 06:02:45 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.18 2007/07/01 07:36:59 xtraeme Exp $");
#include "opt_compat_netbsd.h"
#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/vnode.h>
#include <sys/condvar.h>
#include <sys/mutex.h>
#include <dev/sysmon/sysmonvar.h>
static LIST_HEAD(, sysmon_pswitch) sysmon_pswitch_list =
LIST_HEAD_INITIALIZER(sysmon_pswitch_list);
static struct simplelock sysmon_pswitch_list_slock =
SIMPLELOCK_INITIALIZER;
static kmutex_t sysmon_power_event_queue_mtx;
static kcondvar_t sysmon_power_event_queue_cv;
static struct proc *sysmon_power_daemon;
static prop_dictionary_t sysmon_power_dict;
#define SYSMON_MAX_POWER_EVENTS 32
struct power_event_description {
int type;
const char *desc;
};
/*
* Available events for power switches.
*/
static const struct power_event_description pswitch_event_desc[] = {
{ PSWITCH_EVENT_PRESSED, "pressed" },
{ PSWITCH_EVENT_RELEASED, "released" },
{ -1, NULL }
};
/*
* Available script names for power switches.
*/
static const struct power_event_description pswitch_type_desc[] = {
{ PSWITCH_TYPE_POWER, "power_button" },
{ PSWITCH_TYPE_SLEEP, "sleep_button" },
{ PSWITCH_TYPE_LID, "lid_button" },
{ PSWITCH_TYPE_RESET, "reset_button" },
{ PSWITCH_TYPE_ACADAPTER, "acadapter" },
{ -1, NULL }
};
/*
* Available events for envsys(4).
*/
static const struct power_event_description penvsys_event_desc[] = {
{ PENVSYS_EVENT_NORMAL, "normal" },
{ PENVSYS_EVENT_CRITICAL, "critical" },
{ PENVSYS_EVENT_CRITOVER, "critical-over" },
{ PENVSYS_EVENT_CRITUNDER, "critical-under" },
{ PENVSYS_EVENT_WARNOVER, "warning-over" },
{ PENVSYS_EVENT_WARNUNDER, "warning-under" },
{ PENVSYS_EVENT_USER_CRITMAX, "critical-over" },
{ PENVSYS_EVENT_USER_CRITMIN, "critical-under" },
{ PENVSYS_EVENT_BATT_USERCAP, "user-capacity" },
{ PENVSYS_EVENT_DRIVE_STCHANGED,"state-changed" },
{ -1, NULL }
};
/*
* Available script names for envsys(4).
*/
static const struct power_event_description penvsys_type_desc[] = {
{ PENVSYS_TYPE_BATTERY, "sensor_battery" },
{ PENVSYS_TYPE_DRIVE, "sensor_drive" },
{ PENVSYS_TYPE_FAN, "sensor_fan" },
{ PENVSYS_TYPE_POWER, "sensor_power" },
{ PENVSYS_TYPE_RESISTANCE, "sensor_resistance" },
{ PENVSYS_TYPE_TEMP, "sensor_temperature" },
{ PENVSYS_TYPE_VOLTAGE, "sensor_voltage" },
{ -1, NULL }
};
#define SYSMON_MAX_POWER_EVENTS 32
static struct simplelock sysmon_power_event_queue_slock =
SIMPLELOCK_INITIALIZER;
static power_event_t sysmon_power_event_queue[SYSMON_MAX_POWER_EVENTS];
static int sysmon_power_event_queue_head;
static int sysmon_power_event_queue_tail;
static int sysmon_power_event_queue_count;
static int sysmon_power_event_queue_flags;
static struct selinfo sysmon_power_event_queue_selinfo;
static char sysmon_power_type[32];
#define PEVQ_F_WAITING 0x01 /* daemon waiting for event */
static int sysmon_power_make_dictionary(void *, int, int);
static int sysmon_power_daemon_task(void *, int);
#define SYSMON_NEXT_EVENT(x) (((x) + 1) % SYSMON_MAX_POWER_EVENTS)
/*
* sysmon_power_init:
*
* Initializes the mutexes and condition variables in the
* boot process via init_main.c.
*/
void
sysmon_power_init(void)
{
mutex_init(&sysmon_power_event_queue_mtx, MUTEX_DRIVER, IPL_NONE);
cv_init(&sysmon_power_event_queue_cv, "smpower");
}
/*
* sysmon_queue_power_event:
*
@ -89,17 +194,15 @@ static int
sysmon_queue_power_event(power_event_t *pev)
{
LOCK_ASSERT(simple_lock_held(&sysmon_power_event_queue_slock));
if (sysmon_power_event_queue_count == SYSMON_MAX_POWER_EVENTS)
return (0);
return 0;
sysmon_power_event_queue[sysmon_power_event_queue_head] = *pev;
sysmon_power_event_queue_head =
SYSMON_NEXT_EVENT(sysmon_power_event_queue_head);
sysmon_power_event_queue_count++;
return (1);
return 1;
}
/*
@ -111,18 +214,15 @@ sysmon_queue_power_event(power_event_t *pev)
static int
sysmon_get_power_event(power_event_t *pev)
{
LOCK_ASSERT(simple_lock_held(&sysmon_power_event_queue_slock));
if (sysmon_power_event_queue_count == 0)
return (0);
return 0;
*pev = sysmon_power_event_queue[sysmon_power_event_queue_tail];
sysmon_power_event_queue_tail =
SYSMON_NEXT_EVENT(sysmon_power_event_queue_tail);
sysmon_power_event_queue_count--;
return (1);
return 1;
}
/*
@ -133,11 +233,101 @@ sysmon_get_power_event(power_event_t *pev)
static void
sysmon_power_event_queue_flush(void)
{
sysmon_power_event_queue_head = 0;
sysmon_power_event_queue_tail = 0;
sysmon_power_event_queue_count = 0;
sysmon_power_event_queue_flags = 0;
}
/*
* sysmon_power_daemon_task:
*
* Assign required power event members and sends a signal
* to the process to notify that an event was enqueued succesfully.
*/
static int
sysmon_power_daemon_task(void *pev_data, int event)
{
power_event_t pev;
int rv, error = 0;
/*
* If a power management daemon is connected, then simply
* deliver the event to them. If not, we need to try to
* do something reasonable ourselves.
*/
switch (event) {
/* Power switch events */
case PSWITCH_EVENT_PRESSED:
case PSWITCH_EVENT_RELEASED:
{
struct sysmon_pswitch *pswitch =
(struct sysmon_pswitch *)pev_data;
pev.pev_type = POWER_EVENT_SWITCH_STATE_CHANGE;
#ifdef COMPAT_40
pev.pev_switch.psws_state = event;
pev.pev_switch.psws_type = pswitch->smpsw_type;
if (pswitch->smpsw_name) {
(void)strlcpy(pev.pev_switch.psws_name,
pswitch->smpsw_name,
sizeof(pev.pev_switch.psws_name));
}
#endif
error = sysmon_power_make_dictionary(pswitch,
event,
pev.pev_type);
if (error)
goto out;
break;
}
/* Power envsys events */
case PENVSYS_EVENT_NORMAL:
case PENVSYS_EVENT_CRITICAL:
case PENVSYS_EVENT_CRITUNDER:
case PENVSYS_EVENT_CRITOVER:
case PENVSYS_EVENT_WARNUNDER:
case PENVSYS_EVENT_WARNOVER:
case PENVSYS_EVENT_USER_CRITMAX:
case PENVSYS_EVENT_USER_CRITMIN:
case PENVSYS_EVENT_BATT_USERCAP:
case PENVSYS_EVENT_DRIVE_STCHANGED:
{
struct penvsys_state *penvsys =
(struct penvsys_state *)pev_data;
pev.pev_type = POWER_EVENT_ENVSYS_STATE_CHANGE;
error = sysmon_power_make_dictionary(penvsys,
event,
pev.pev_type);
if (error)
goto out;
break;
}
default:
error = ENOTTY;
goto out;
}
rv = sysmon_queue_power_event(&pev);
if (rv == 0) {
printf("%s: WARNING: state change event %d lost; "
"queue full\n", __func__, pev.pev_type);
error = EINVAL;
goto out;
} else {
cv_broadcast(&sysmon_power_event_queue_cv);
mutex_exit(&sysmon_power_event_queue_mtx);
selnotify(&sysmon_power_event_queue_selinfo, 0);
}
out:
return error;
}
/*
@ -146,21 +336,20 @@ sysmon_power_event_queue_flush(void)
* Open the system monitor device.
*/
int
sysmonopen_power(dev_t dev, int flag, int mode,
struct lwp *l)
sysmonopen_power(dev_t dev, int flag, int mode, struct lwp *l)
{
int error = 0;
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
if (sysmon_power_daemon != NULL)
error = EBUSY;
else {
sysmon_power_daemon = l->l_proc;
sysmon_power_event_queue_flush();
}
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
return (error);
return error;
}
/*
@ -169,22 +358,21 @@ sysmonopen_power(dev_t dev, int flag, int mode,
* Close the system monitor device.
*/
int
sysmonclose_power(dev_t dev, int flag, int mode,
struct lwp *l)
sysmonclose_power(dev_t dev, int flag, int mode, struct lwp *l)
{
int count;
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
count = sysmon_power_event_queue_count;
sysmon_power_daemon = NULL;
sysmon_power_event_queue_flush();
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
if (count)
printf("WARNING: %d power events lost by exiting daemon\n",
count);
printf("WARNING: %d power event%s lost by exiting daemon\n",
count, count > 1 ? "s" : "");
return (0);
return 0;
}
/*
@ -196,32 +384,27 @@ int
sysmonread_power(dev_t dev, struct uio *uio, int flags)
{
power_event_t pev;
int error;
/* We only allow one event to be read at a time. */
if (uio->uio_resid != POWER_EVENT_MSG_SIZE)
return (EINVAL);
return EINVAL;
simple_lock(&sysmon_power_event_queue_slock);
again:
if (sysmon_get_power_event(&pev)) {
simple_unlock(&sysmon_power_event_queue_slock);
return (uiomove(&pev, POWER_EVENT_MSG_SIZE, uio));
}
mutex_enter(&sysmon_power_event_queue_mtx);
for (;;) {
if (sysmon_get_power_event(&pev)) {
mutex_exit(&sysmon_power_event_queue_mtx);
return uiomove(&pev, POWER_EVENT_MSG_SIZE, uio);
}
if (flags & IO_NDELAY) {
simple_unlock(&sysmon_power_event_queue_slock);
return (EWOULDBLOCK);
}
if (flags & IO_NDELAY) {
mutex_exit(&sysmon_power_event_queue_mtx);
return EWOULDBLOCK;
}
sysmon_power_event_queue_flags |= PEVQ_F_WAITING;
error = ltsleep(&sysmon_power_event_queue_count,
PRIBIO|PCATCH, "smpower", 0, &sysmon_power_event_queue_slock);
if (error) {
simple_unlock(&sysmon_power_event_queue_slock);
return (error);
cv_wait(&sysmon_power_event_queue_cv,
&sysmon_power_event_queue_mtx);
}
goto again;
mutex_exit(&sysmon_power_event_queue_mtx);
}
/*
@ -238,37 +421,37 @@ sysmonpoll_power(dev_t dev, int events, struct lwp *l)
/* Attempt to save some work. */
if ((events & (POLLIN | POLLRDNORM)) == 0)
return (revents);
return revents;
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
if (sysmon_power_event_queue_count)
revents |= events & (POLLIN | POLLRDNORM);
else
selrecord(l, &sysmon_power_event_queue_selinfo);
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
return (revents);
return revents;
}
static void
filt_sysmon_power_rdetach(struct knote *kn)
{
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
SLIST_REMOVE(&sysmon_power_event_queue_selinfo.sel_klist,
kn, knote, kn_selnext);
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
}
static int
filt_sysmon_power_read(struct knote *kn, long hint)
{
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
kn->kn_data = sysmon_power_event_queue_count;
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
return (kn->kn_data > 0);
return kn->kn_data > 0;
}
static const struct filterops sysmon_power_read_filtops =
@ -299,14 +482,14 @@ sysmonkqfilter_power(dev_t dev, struct knote *kn)
break;
default:
return (1);
return 1;
}
simple_lock(&sysmon_power_event_queue_slock);
mutex_enter(&sysmon_power_event_queue_mtx);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
return (0);
return 0;
}
/*
@ -315,8 +498,7 @@ sysmonkqfilter_power(dev_t dev, struct knote *kn)
* Perform a power managmenet control request.
*/
int
sysmonioctl_power(dev_t dev, u_long cmd, void *data,
int flag, struct lwp *l)
sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
int error = 0;
@ -325,14 +507,133 @@ sysmonioctl_power(dev_t dev, u_long cmd, void *data,
{
struct power_type *power_type = (void *) data;
strcpy(power_type->power_type, sysmon_power_type);
(void)strlcpy(power_type->power_type,
sysmon_power_type,
sizeof(power_type->power_type));
break;
}
case POWER_EVENT_RECVDICT:
{
struct plistref *plist = (struct plistref *)data;
if (!sysmon_power_dict) {
error = ENOTSUP;
break;
}
error = prop_dictionary_copyout_ioctl(plist,
cmd,
sysmon_power_dict);
break;
}
default:
error = ENOTTY;
}
return (error);
return error;
}
/*
* sysmon_power_make_dictionary:
*
* Creates a dictionary with all properties specified in the
* sysmon_pswitch or sysmon_penvsys struct.
*/
int
sysmon_power_make_dictionary(void *power_data, int event, int type)
{
int i = 0;
mutex_exit(&sysmon_power_event_queue_mtx);
/*
* if there's a dictionary already created, destroy it
* and make a new one to make sure it's always the latest
* used by the event.
*/
if (sysmon_power_dict)
prop_object_release(sysmon_power_dict);
sysmon_power_dict = prop_dictionary_create();
mutex_enter(&sysmon_power_event_queue_mtx);
switch (type) {
/*
* create the dictionary for a power switch event.
*/
case POWER_EVENT_SWITCH_STATE_CHANGE:
{
const struct power_event_description *peevent =
pswitch_event_desc;
const struct power_event_description *petype =
pswitch_type_desc;
struct sysmon_pswitch *smpsw =
(struct sysmon_pswitch *)power_data;
const char *pwrtype = "pswitch";
#define SETPROP(key, str) \
do { \
if ((str) && \
!prop_dictionary_set_cstring_nocopy(sysmon_power_dict, \
(key), \
(str))) { \
printf("%s: failed to set %s\n", __func__, (str)); \
return EINVAL; \
} \
} while (/* CONSTCOND */ 0)
SETPROP("driver-name", smpsw->smpsw_name);
for (i = 0; peevent[i].type != -1; i++)
if (peevent[i].type == event)
break;
SETPROP("powerd-event-name", peevent[i].desc);
for (i = 0; petype[i].type != -1; i++)
if (petype[i].type == smpsw->smpsw_type)
break;
SETPROP("powerd-script-name", petype[i].desc);
SETPROP("power-type", pwrtype);
break;
}
/*
* create a dictionary for power envsys event.
*/
case POWER_EVENT_ENVSYS_STATE_CHANGE:
{
const struct power_event_description *peevent =
penvsys_event_desc;
const struct power_event_description *petype =
penvsys_type_desc;
struct penvsys_state *pes =
(struct penvsys_state *)power_data;
const char *pwrtype = "envsys";
SETPROP("driver-name", pes->pes_dvname);
SETPROP("sensor-name", pes->pes_sensname);
SETPROP("drive-state-desc", pes->pes_statedesc);
for (i = 0; peevent[i].type != -1; i++)
if (peevent[i].type == event)
break;
SETPROP("powerd-event-name", peevent[i].desc);
for (i = 0; petype[i].type != -1; i++)
if (petype[i].type == pes->pes_type)
break;
SETPROP("powerd-script-name", petype[i].desc);
SETPROP("power-type", pwrtype);
break;
}
default:
return ENOTSUP;
}
return 0;
}
/*
@ -350,7 +651,107 @@ sysmon_power_settype(const char *type)
* during autoconfiguration, and then only read from
* then on.
*/
strcpy(sysmon_power_type, type);
(void)strlcpy(sysmon_power_type, type, sizeof(sysmon_power_type));
}
#define PENVSYS_SHOWSTATE(str) \
do { \
printf("%s: %s limit on '%s'\n", \
pes->pes_dvname, (str), pes->pes_sensname); \
} while (/* CONSTCOND */ 0)
/*
* sysmon_penvsys_event:
*
* Puts an event onto the sysmon power queue and sends the
* appropiate event.
*/
void
sysmon_penvsys_event(struct penvsys_state *pes, int event)
{
const char *mystr = NULL;
mutex_enter(&sysmon_power_event_queue_mtx);
if (sysmon_power_daemon != NULL)
if (sysmon_power_daemon_task(pes, event) == 0)
return;
mutex_exit(&sysmon_power_event_queue_mtx);
switch (pes->pes_type) {
case PENVSYS_TYPE_BATTERY:
switch (event) {
case PENVSYS_EVENT_WARNUNDER:
mystr = "warning capacity";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_CRITUNDER:
mystr = "low capacity";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_CRITICAL:
case PENVSYS_EVENT_BATT_USERCAP:
mystr = "critical capacity";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_NORMAL:
printf("%s: acceptable capacity on '%s'\n",
pes->pes_dvname, pes->pes_sensname);
break;
}
break;
case PENVSYS_TYPE_TEMP:
case PENVSYS_TYPE_POWER:
case PENVSYS_TYPE_RESISTANCE:
case PENVSYS_TYPE_VOLTAGE:
case PENVSYS_TYPE_FAN:
switch (event) {
case PENVSYS_EVENT_CRITICAL:
mystr = "critical";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_CRITOVER:
case PENVSYS_EVENT_USER_CRITMAX:
mystr = "critical over";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_CRITUNDER:
case PENVSYS_EVENT_USER_CRITMIN:
mystr = "critical under";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_WARNOVER:
mystr = "warning over";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_WARNUNDER:
mystr = "warning under";
PENVSYS_SHOWSTATE(mystr);
break;
case PENVSYS_EVENT_NORMAL:
printf("%s: normal state on '%s'\n",
pes->pes_dvname, pes->pes_sensname);
break;
default:
printf("%s: unknown event\n", __func__);
}
break;
case PENVSYS_TYPE_DRIVE:
switch (event) {
case PENVSYS_EVENT_DRIVE_STCHANGED:
printf("%s: state changed on '%s' to '%s'\n",
pes->pes_dvname, pes->pes_sensname,
pes->pes_statedesc);
case PENVSYS_EVENT_NORMAL:
printf("%s: normal state on '%s' (%s)\n",
pes->pes_dvname, pes->pes_sensname,
pes->pes_statedesc);
break;
}
break;
default:
printf("%s: unknown power type\n", __func__);
break;
}
}
/*
@ -361,12 +762,8 @@ sysmon_power_settype(const char *type)
int
sysmon_pswitch_register(struct sysmon_pswitch *smpsw)
{
simple_lock(&sysmon_pswitch_list_slock);
LIST_INSERT_HEAD(&sysmon_pswitch_list, smpsw, smpsw_list);
simple_unlock(&sysmon_pswitch_list_slock);
return (0);
/* nada */
return 0;
}
/*
@ -377,10 +774,7 @@ sysmon_pswitch_register(struct sysmon_pswitch *smpsw)
void
sysmon_pswitch_unregister(struct sysmon_pswitch *smpsw)
{
simple_lock(&sysmon_pswitch_list_slock);
LIST_REMOVE(smpsw, smpsw_list);
simple_unlock(&sysmon_pswitch_list_slock);
/* nada */
}
/*
@ -391,43 +785,12 @@ sysmon_pswitch_unregister(struct sysmon_pswitch *smpsw)
void
sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event)
{
/*
* If a power management daemon is connected, then simply
* deliver the event to them. If not, we need to try to
* do something reasonable ourselves.
*/
simple_lock(&sysmon_power_event_queue_slock);
if (sysmon_power_daemon != NULL) {
power_event_t pev;
int rv;
pev.pev_type = POWER_EVENT_SWITCH_STATE_CHANGE;
pev.pev_switch.psws_state = event;
pev.pev_switch.psws_type = smpsw->smpsw_type;
strcpy(pev.pev_switch.psws_name, smpsw->smpsw_name);
rv = sysmon_queue_power_event(&pev);
if (rv == 0) {
simple_unlock(&sysmon_power_event_queue_slock);
printf("%s: WARNING: state change event %d lost; "
"queue full\n", smpsw->smpsw_name,
pev.pev_type);
mutex_enter(&sysmon_power_event_queue_mtx);
if (sysmon_power_daemon != NULL)
if (sysmon_power_daemon_task(smpsw, event) == 0)
return;
} else {
if (sysmon_power_event_queue_flags & PEVQ_F_WAITING) {
sysmon_power_event_queue_flags &= ~PEVQ_F_WAITING;
simple_unlock(&sysmon_power_event_queue_slock);
wakeup(&sysmon_power_event_queue_count);
} else {
simple_unlock(&sysmon_power_event_queue_slock);
}
selnotify(&sysmon_power_event_queue_selinfo, 0);
return;
}
}
simple_unlock(&sysmon_power_event_queue_slock);
mutex_exit(&sysmon_power_event_queue_mtx);
switch (smpsw->smpsw_type) {
case PSWITCH_TYPE_POWER:
if (event != PSWITCH_EVENT_PRESSED) {
@ -515,8 +878,5 @@ sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event)
}
break;
default:
printf("%s: sysmon_pswitch_event can't handle me.\n",
smpsw->smpsw_name);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysmonvar.h,v 1.14 2007/05/08 20:04:42 xtraeme Exp $ */
/* $NetBSD: sysmonvar.h,v 1.15 2007/07/01 07:37:01 xtraeme Exp $ */
/*-
* Copyright (c) 2000 Zembu Labs, Inc.
@ -36,6 +36,9 @@
#ifndef _DEV_SYSMON_SYSMONVAR_H_
#define _DEV_SYSMON_SYSMONVAR_H_
#ifndef _LKM
#include "opt_compat_netbsd.h"
#endif
#include <sys/envsys.h>
#include <sys/wdog.h>
#include <sys/power.h>
@ -55,35 +58,38 @@ struct uio;
*****************************************************************************/
struct sysmon_envsys {
int32_t sme_envsys_version; /* ENVSYS API version */
const char *sme_name; /* envsys device name */
uint32_t sme_nsensors; /* sensor count, from driver */
int sme_flags; /* additional flags */
#define SME_FLAG_BUSY 0x00000001 /* sme is busy */
#define SME_FLAG_WANTED 0x00000002 /* someone waiting for this */
#define SME_DISABLE_GTREDATA 0x00000004 /* disable sme_gtredata */
envsys_data_t *sme_sensor_data; /* pointer to device data */
/* linked list for the sysmon envsys devices */
LIST_ENTRY(sysmon_envsys) sme_list;
const struct envsys_range *sme_ranges;
struct envsys_basic_info *sme_sensor_info;
struct envsys_tre_data *sme_sensor_data;
void *sme_cookie; /* for ENVSYS back-end */
void *sme_cookie; /* for ENVSYS back-end */
/* Callbacks */
int (*sme_gtredata)(struct sysmon_envsys *, struct envsys_tre_data *);
int (*sme_streinfo)(struct sysmon_envsys *, struct envsys_basic_info *);
/* Function callback to recieve data from device */
int (*sme_gtredata)(struct sysmon_envsys *, envsys_data_t *);
#ifdef COMPAT_40
u_int sme_fsensor; /* sensor index base, from sysmon */
u_int sme_nsensors; /* sensor count, from driver */
int sme_flags; /* SME_FLAG_ flags defined below */
#define SME_SENSOR_IDX(sme, idx) ((idx) - (sme)->sme_fsensor)
#endif
};
#define SME_FLAG_BUSY 0x00000001 /* sme is busy */
#define SME_FLAG_WANTED 0x00000002 /* someone waiting for this */
#define SME_SENSOR_IDX(sme, idx) ((idx) - (sme)->sme_fsensor)
int sysmonopen_envsys(dev_t, int, int, struct lwp *);
int sysmonclose_envsys(dev_t, int, int, struct lwp *);
int sysmonioctl_envsys(dev_t, u_long, void *, int, struct lwp *);
int sysmon_envsys_register(struct sysmon_envsys *);
void sysmon_envsys_unregister(struct sysmon_envsys *);
struct sysmon_envsys *sysmon_envsys_find(const char *);
void sysmon_envsys_init(void);
/*****************************************************************************
* Watchdog timer support
@ -134,5 +140,8 @@ int sysmon_pswitch_register(struct sysmon_pswitch *);
void sysmon_pswitch_unregister(struct sysmon_pswitch *);
void sysmon_pswitch_event(struct sysmon_pswitch *, int);
void sysmon_penvsys_event(struct penvsys_state *, int);
void sysmon_power_init(void);
#endif /* _DEV_SYSMON_SYSMONVAR_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: init_main.c,v 1.304 2007/06/17 13:34:43 yamt Exp $ */
/* $NetBSD: init_main.c,v 1.305 2007/07/01 07:36:39 xtraeme Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.304 2007/06/17 13:34:43 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.305 2007/07/01 07:36:39 xtraeme Exp $");
#include "opt_ipsec.h"
#include "opt_kcont.h"
@ -87,6 +87,8 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.304 2007/06/17 13:34:43 yamt Exp $")
#include "opt_pax.h"
#include "rnd.h"
#include "sysmon_envsys.h"
#include "sysmon_power.h"
#include "veriexec.h"
#include <sys/param.h>
@ -177,6 +179,9 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.304 2007/06/17 13:34:43 yamt Exp $")
#include <uvm/uvm.h>
#include <dev/cons.h>
#if NSYSMON_ENVSYS > 0 || NSYSMON_POWER > 0
#include <dev/sysmon/sysmonvar.h>
#endif
#include <net/if.h>
#include <net/raw_cb.h>
@ -362,6 +367,12 @@ main(void)
/* Initialize asynchronous I/O. */
aio_sysinit();
#if NSYSMON_ENVSYS > 0
sysmon_envsys_init();
#endif
#if NSYSMON_POWER > 0
sysmon_power_init();
#endif
#ifdef __HAVE_TIMECOUNTER
inittimecounter();
ntp_init();

View File

@ -1,11 +1,11 @@
/* $NetBSD: envsys.h,v 1.11 2007/05/01 17:18:56 bouyer Exp $ */
/* $NetBSD: envsys.h,v 1.12 2007/07/01 07:36:40 xtraeme Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Tim Rightnour and Bill Squier.
* by Tim Rightnour, Juan Romero Pardines and Bill Squier.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -39,22 +39,103 @@
#ifndef _SYS_ENVSYS_H_
#define _SYS_ENVSYS_H_
#ifndef _KERNEL
#include <stdbool.h>
#endif
#include <sys/ioccom.h>
#include <sys/power.h>
/* Returns API Version * 1000 */
/*
* ENVironmental SYStem version 2 (aka ENVSYS 2)
*/
#define ENVSYS_VERSION _IOR('E', 0, int32_t)
#define ENVSYS_MAXSENSORS 512
#define ENVSYS_DESCLEN 32
/* returns the range for a particular sensor */
struct envsys_range {
u_int low;
u_int high;
u_int units; /* see GTREDATA */
/* struct used by a device sensor */
struct envsys_data {
uint32_t sensor; /* sensor number */
uint32_t units; /* type of sensor */
uint32_t state; /* sensor state */
uint32_t flags; /* sensor flags */
uint32_t rpms; /* for fans, nominal RPMs */
int32_t rfact; /* for volts, factor x 10^4 */
int32_t value_cur; /* current value */
int32_t value_max; /* max value */
int32_t value_min; /* min value */
int32_t value_avg; /* avg value */
bool monitor; /* monitoring enabled/disabled */
char desc[ENVSYS_DESCLEN]; /* sensor description */
};
typedef struct envsys_range envsys_range_t;
#define ENVSYS_GRANGE _IOWR('E', 1, envsys_range_t)
typedef struct envsys_data envsys_data_t;
/* sensor units */
enum envsys_units {
ENVSYS_STEMP = 0, /* Temperature */
ENVSYS_SFANRPM, /* Fan RPM */
ENVSYS_SVOLTS_AC, /* AC Volts */
ENVSYS_SVOLTS_DC, /* DC Volts */
ENVSYS_SOHMS, /* Ohms */
ENVSYS_SWATTS, /* Watts */
ENVSYS_SAMPS, /* Ampere */
ENVSYS_SWATTHOUR, /* Watt hour */
ENVSYS_SAMPHOUR, /* Ampere hour */
ENVSYS_INDICATOR, /* Indicator */
ENVSYS_INTEGER, /* Integer */
ENVSYS_DRIVE, /* Drive */
ENVSYS_NSENSORS
};
/* sensor states */
enum envsys_states {
ENVSYS_SVALID = 10, /* sensor state is valid */
ENVSYS_SINVALID, /* sensor state is invalid */
ENVSYS_SCRITICAL, /* sensor state is critical */
ENVSYS_SCRITUNDER, /* sensor state is critical under */
ENVSYS_SCRITOVER, /* sensor state is critical over */
ENVSYS_SWARNUNDER, /* sensor state is warn under */
ENVSYS_SWARNOVER /* sensor state is warn over */
};
/* sensor drive states */
enum envsys_drive_states {
ENVSYS_DRIVE_EMPTY = 1, /* drive is empty */
ENVSYS_DRIVE_READY, /* drive is ready */
ENVSYS_DRIVE_POWERUP, /* drive is powered up */
ENVSYS_DRIVE_ONLINE, /* drive is online */
ENVSYS_DRIVE_IDLE, /* drive is idle */
ENVSYS_DRIVE_ACTIVE, /* drive is active */
ENVSYS_DRIVE_REBUILD, /* drive is rebuilding */
ENVSYS_DRIVE_POWERDOWN, /* drive is powered down */
ENVSYS_DRIVE_FAIL, /* drive failed */
ENVSYS_DRIVE_PFAIL /* drive is degraded */
};
/* sensor flags */
#define ENVSYS_FPERCENT 0x00000001 /* sensor wants a percentage */
#define ENVSYS_FVALID_MAX 0x00000002 /* max value is ok */
#define ENVSYS_FVALID_MIN 0x00000004 /* min value is ok */
#define ENVSYS_FVALID_AVG 0x00000008 /* avg value is ok */
#define ENVSYS_FCHANGERFACT 0x00000010 /* sensor can change rfact */
/* monitoring flags */
#define ENVSYS_FMONCRITICAL 0x00000020 /* monitor a critical state */
#define ENVSYS_FMONCRITUNDER 0x00000040 /* monitor a critunder state */
#define ENVSYS_FMONCRITOVER 0x00000080 /* monitor a critover state */
#define ENVSYS_FMONWARNUNDER 0x00000100 /* monitor a warnunder state */
#define ENVSYS_FMONWARNOVER 0x00000200 /* monitor a warnover state */
#define ENVSYS_FMONDRVSTATE 0x00000400 /* monitor a drive state */
#define ENVSYS_FMONNOTSUPP 0x00000800 /* monitoring not supported */
#define ENVSYS_GETDICTIONARY _IOWR('E', 0, struct plistref)
#define ENVSYS_SETDICTIONARY _IOWR('E', 1, struct plistref)
/*
* Compatibility with old interface. Only ENVSYS_GTREDATA
* and ENVSYS_GTREINFO ioctls are supported.
*/
/* get sensor data */
@ -70,9 +151,6 @@ struct envsys_tre_data {
uint32_t validflags; /* sensor valid flags */
u_int units; /* type of sensor */
};
typedef struct envsys_tre_data envsys_temp_data_t;
typedef struct envsys_tre_data envsys_rpm_data_t;
typedef struct envsys_tre_data envsys_electrical_data_t;
typedef struct envsys_tre_data envsys_tre_data_t;
/* flags for warnflags */
@ -82,23 +160,6 @@ typedef struct envsys_tre_data envsys_tre_data_t;
#define ENVSYS_WARN_OVER 0x00000004 /* an over condition */
#define ENVSYS_WARN_CRITOVER 0x00000008 /* a critical over condition */
/* type of sensor for units */
enum envsys_units {
ENVSYS_STEMP = 0,
ENVSYS_SFANRPM,
ENVSYS_SVOLTS_AC,
ENVSYS_SVOLTS_DC,
ENVSYS_SOHMS,
ENVSYS_SWATTS,
ENVSYS_SAMPS,
ENVSYS_SWATTHOUR,
ENVSYS_SAMPHOUR,
ENVSYS_INDICATOR, /* boolean indicator */
ENVSYS_INTEGER, /* generic integer return */
ENVSYS_DRIVE, /* disk status */
ENVSYS_NSENSORS
};
/* drive status */
#define ENVSYS_DRIVE_EMPTY 1
#define ENVSYS_DRIVE_READY 2
@ -143,12 +204,8 @@ struct envsys_basic_info {
u_int rpms; /* for fans, set nominal RPMs */
uint32_t validflags; /* sensor valid flags */
};
typedef struct envsys_basic_info envsys_temp_info_t;
typedef struct envsys_basic_info envsys_rpm_info_t;
typedef struct envsys_basic_info envsys_electrical_info_t;
typedef struct envsys_basic_info envsys_basic_info_t;
#define ENVSYS_STREINFO _IOWR('E', 3, envsys_basic_info_t)
#define ENVSYS_GTREINFO _IOWR('E', 4, envsys_basic_info_t)
#endif /* _SYS_ENVSYS_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: power.h,v 1.4 2005/12/11 12:25:20 christos Exp $ */
/* $NetBSD: power.h,v 1.5 2007/07/01 07:36:41 xtraeme Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -78,6 +78,7 @@
* Lid switch This is e.g. the lid of a laptop. This kind
* of switch has state. We know if it is open
* or closed.
*
*/
#define PSWITCH_TYPE_POWER 0 /* power button */
@ -86,19 +87,11 @@
#define PSWITCH_TYPE_RESET 3 /* reset button */
#define PSWITCH_TYPE_ACADAPTER 4 /* AC adapter presence */
#define PSWITCH_EVENT_PRESSED 0 /* button pressed, lid closed,
AC adapter online */
#define PSWITCH_EVENT_RELEASED 1 /* button released, lid open,
AC adapter offline */
#define PSWITCH_STATE_PRESSED 0 /* button pressed/lid closed */
#define PSWITCH_STATE_RELEASED 1 /* button released/lid open */
#define PSWITCH_STATE_UNKNOWN -1
#define PSWITCH_EVENT_PRESSED 0 /* button pressed, lid closed, AC off */
#define PSWITCH_EVENT_RELEASED 1 /* button released, lid open, AC on */
/*
* This structure describes the state of a power switch. It is used
* by the POWER_IOC_GET_SWSTATE ioctl, as well as in power mangement
* event messages.
* This structure describes the state of a power switch.
*/
struct pswitch_state {
char psws_name[16]; /* power switch name */
@ -106,6 +99,102 @@ struct pswitch_state {
int32_t psws_state; /* state of the switch/event */
};
/*
* envsys(4) events:
*
* envsys events are sent by the sysmon envsys framework when
* a critical condition happens in a sensor.
*
* We define the folowing types of envsys events:
*
* sensor temperature To handle temperature sensors.
*
* sensor voltage To handle voltage sensors (AC/DC).
*
* sensor power To handle power sensors (W/Ampere).
*
* sensor resistance To handle resistance sensors (Ohms).
*
* sensor battery To handle battery sensors (Ah/Wh).
*
* sensor fan To handle fan sensors.
*
* sensor drive To handle drive sensors.
*
*/
#define PENVSYS_TYPE_TEMP 10
#define PENVSYS_TYPE_VOLTAGE 11
#define PENVSYS_TYPE_POWER 12
#define PENVSYS_TYPE_RESISTANCE 13
#define PENVSYS_TYPE_BATTERY 14
#define PENVSYS_TYPE_FAN 15
#define PENVSYS_TYPE_DRIVE 16
/*
* The following events apply for temperatures, power, resistance,
* voltages, battery and fan sensors:
*
* PENVSYS_EVENT_CRITICAL A critical limit.
*
* PENVSYS_EVENT_CRITOVER A critical over limit.
*
* PENVSYS_EVENT_CRITUNDER A critical under limit.
*
* PENVSYS_EVENT_WARNOVER A warning under limit.
*
* PENVSYS_EVENT_WARNUNDER A warning over limit.
*
* The following events apply to the same except for batteries:
*
* PENVSYS_EVENT_USER_CRITMAX User critical max limit.
*
* PENVSYS_EVENT_USER_CRITMIN User critical min limit.
*
* The folowing event apply to all sensors, when the state is
* valid or the critical limit is not valid anymore:
*
* PENVSYS_EVENT_NORMAL Normal state in the sensor.
*/
#define PENVSYS_EVENT_NORMAL 90
#define PENVSYS_EVENT_CRITICAL 100
#define PENVSYS_EVENT_CRITOVER 110
#define PENVSYS_EVENT_CRITUNDER 120
#define PENVSYS_EVENT_WARNOVER 130
#define PENVSYS_EVENT_WARNUNDER 140
#define PENVSYS_EVENT_USER_CRITMAX 150
#define PENVSYS_EVENT_USER_CRITMIN 160
/*
* The following events apply for battery sensors:
*
* PENVSYS_EVENT_BATT_USERCAP User capacity.
*
*/
#define PENVSYS_EVENT_BATT_USERCAP 170
/*
* The following events apply for drive sensors:
*
* PENVSYS_EVENT_DRIVE_STCHANGED Drive state changed.
*
*/
#define PENVSYS_EVENT_DRIVE_STCHANGED 180
/*
* This structure defines the properties of an envsys event.
*/
struct penvsys_state {
char pes_dvname[16]; /* device name */
char pes_sensname[32]; /* sensor name */
char pes_statedesc[64]; /* sensor state description */
int32_t pes_type; /* envsys power type */
int32_t pes_state; /* state for the event */
};
/*
* Power management event messages:
*
@ -115,23 +204,26 @@ struct pswitch_state {
#define POWER_EVENT_MSG_SIZE 32
#define POWER_EVENT_SWITCH_STATE_CHANGE 0
#define POWER_EVENT_ENVSYS_STATE_CHANGE 1
typedef struct {
typedef struct power_event {
int32_t pev_type; /* power event type */
union {
int32_t _pev_d_space[(POWER_EVENT_MSG_SIZE /
sizeof(int32_t)) - 1];
int32_t _pev_d_space[(POWER_EVENT_MSG_SIZE /
sizeof(int32_t)) - 1];
/*
* This field is used for:
*
* POWER_EVENT_SWITCH_STATE_CHANGE
* POWER_EVENT_SWITCH_STATE_CHANGE
*/
struct pswitch_state _pev_d_switch;
} _pev_data;
} power_event_t;
#define pev_switch _pev_data._pev_d_switch
#define pev_switch _pev_data._pev_d_switch
#define POWER_EVENT_RECVDICT _IOWR('P', 1, struct plistref)
/*
* POWER_IOC_GET_TYPE: