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:
parent
be8757ef61
commit
bf4558f8cf
@ -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
577
sys/dev/sysmon/sysmon_envsys_events.c
Normal file
577
sys/dev/sysmon/sysmon_envsys_events.c
Normal 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); */
|
||||
}
|
190
sys/dev/sysmon/sysmon_envsysvar.h
Normal file
190
sys/dev/sysmon/sysmon_envsysvar.h
Normal 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_ */
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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();
|
||||
|
131
sys/sys/envsys.h
131
sys/sys/envsys.h
@ -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_ */
|
||||
|
126
sys/sys/power.h
126
sys/sys/power.h
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user