Home | History | Annotate | Line # | Download | only in sysmon
sysmon_envsys_events.c revision 1.105
      1 /* $NetBSD: sysmon_envsys_events.c,v 1.105 2012/09/06 12:21:40 pgoyette Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007, 2008 Juan Romero Pardines.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * sysmon_envsys(9) events framework.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.105 2012/09/06 12:21:40 pgoyette Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/types.h>
     37 #include <sys/conf.h>
     38 #include <sys/errno.h>
     39 #include <sys/kernel.h>
     40 #include <sys/systm.h>
     41 #include <sys/proc.h>
     42 #include <sys/mutex.h>
     43 #include <sys/kmem.h>
     44 #include <sys/callout.h>
     45 
     46 #include <dev/sysmon/sysmonvar.h>
     47 #include <dev/sysmon/sysmon_envsysvar.h>
     48 
     49 struct sme_sensor_event {
     50 	int		state;
     51 	int		event;
     52 };
     53 
     54 static const struct sme_sensor_event sme_sensor_event[] = {
     55 	{ ENVSYS_SVALID,			PENVSYS_EVENT_NORMAL },
     56 	{ ENVSYS_SCRITOVER, 			PENVSYS_EVENT_CRITOVER },
     57 	{ ENVSYS_SCRITUNDER, 			PENVSYS_EVENT_CRITUNDER },
     58 	{ ENVSYS_SWARNOVER, 			PENVSYS_EVENT_WARNOVER },
     59 	{ ENVSYS_SWARNUNDER,			PENVSYS_EVENT_WARNUNDER },
     60 	{ ENVSYS_BATTERY_CAPACITY_NORMAL,	PENVSYS_EVENT_NORMAL },
     61 	{ ENVSYS_BATTERY_CAPACITY_WARNING,	PENVSYS_EVENT_BATT_WARN },
     62 	{ ENVSYS_BATTERY_CAPACITY_CRITICAL,	PENVSYS_EVENT_BATT_CRIT },
     63 	{ ENVSYS_BATTERY_CAPACITY_HIGH,		PENVSYS_EVENT_BATT_HIGH },
     64 	{ ENVSYS_BATTERY_CAPACITY_MAX,		PENVSYS_EVENT_BATT_MAX },
     65 	{ -1, 					-1 }
     66 };
     67 
     68 static bool sysmon_low_power;
     69 
     70 #define SME_EVTIMO	(SME_EVENTS_DEFTIMEOUT * hz)
     71 
     72 static bool sme_event_check_low_power(void);
     73 static bool sme_battery_check(void);
     74 static bool sme_battery_critical(envsys_data_t *);
     75 static bool sme_acadapter_check(void);
     76 
     77 static void sme_remove_event(sme_event_t *, struct sysmon_envsys *);
     78 
     79 /*
     80  * sme_event_register:
     81  *
     82  * 	+ Registers a new sysmon envsys event or updates any event
     83  * 	  already in the queue.
     84  */
     85 int
     86 sme_event_register(prop_dictionary_t sdict, envsys_data_t *edata,
     87 		   struct sysmon_envsys *sme, sysmon_envsys_lim_t *lims,
     88 		   uint32_t props, int crittype, int powertype)
     89 {
     90 	sme_event_t *see = NULL, *osee = NULL;
     91 	prop_object_t obj;
     92 	int error = 0;
     93 	const char *objkey;
     94 
     95 	KASSERT(sdict != NULL);
     96 	KASSERT(edata != NULL);
     97 	KASSERT(sme != NULL);
     98 	KASSERT(lims != NULL);
     99 
    100 	/*
    101 	 * Some validation first for limit-checking events
    102 	 *
    103 	 * 1. Limits are not permitted if the units is ENVSYS_INDICATOR
    104 	 *    or ENVSYS_BATTERY_CHARGE.
    105 	 *
    106 	 * 2. Capacity limits are permitted only if the sensor has the
    107 	 *    ENVSYS_FPERCENT flag set and value_max is set.
    108 	 *
    109 	 * 3. It is not permissible for both capacity and value limits
    110 	 *    to coexist.
    111 	 *
    112 	 * Note that it permissible for a sensor to have value limits
    113 	 * even if its ENVSYS_FPERCENT flag and value_max are set.
    114 	 */
    115 
    116 	DPRINTF(("%s: units %d props 0x%04x upropset 0x%04x max_val %d"
    117 		" edata-flags 0x%04x\n", __func__, edata->units, props,
    118 		edata->upropset, edata->value_max, edata->flags));
    119 
    120 	if (props)
    121 		if (edata->units == ENVSYS_INDICATOR ||
    122 		    edata->units == ENVSYS_BATTERY_CHARGE)
    123 			return ENOTSUP;
    124 
    125 	if ((props & PROP_CAP_LIMITS) &&
    126 	    ((edata->value_max == 0) ||
    127 	     !(edata->flags & ENVSYS_FPERCENT) ||
    128 	     (props & PROP_VAL_LIMITS) ||
    129 	     (edata->upropset & PROP_VAL_LIMITS)))
    130 		props = 0;
    131 
    132 	if ((props & PROP_VAL_LIMITS) && (edata->upropset & PROP_CAP_LIMITS))
    133 		props = 0;
    134 
    135 	/*
    136 	 * check if the event is already on the list and return
    137 	 * EEXIST if value provided hasn't been changed.
    138 	 */
    139 	mutex_enter(&sme->sme_mtx);
    140 	LIST_FOREACH(osee, &sme->sme_events_list, see_list) {
    141 		if (strcmp(edata->desc, osee->see_pes.pes_sensname) != 0)
    142 			continue;
    143 		if (crittype != osee->see_type &&
    144 		    osee->see_type != PENVSYS_EVENT_NULL)
    145 			continue;
    146 
    147 		/*
    148 		 * We found an existing event for this sensor.  Make
    149 		 * sure it references the correct edata
    150 		 */
    151 		KASSERT(edata == osee->see_edata);
    152 
    153 		DPRINTF(("%s: dev %s sensor %s: event type %d exists\n",
    154 		    __func__, sme->sme_name, edata->desc, crittype));
    155 
    156 		see = osee;
    157 		if (props & edata->upropset & (PROP_CRITMAX | PROP_BATTMAX)) {
    158 			if (lims->sel_critmax == edata->limits.sel_critmax) {
    159 				DPRINTF(("%s: critmax exists\n", __func__));
    160 				error = EEXIST;
    161 				props &= ~(PROP_CRITMAX | PROP_BATTMAX);
    162 			}
    163 		}
    164 		if (props & edata->upropset & (PROP_WARNMAX | PROP_BATTHIGH)) {
    165 			if (lims->sel_warnmax == edata->limits.sel_warnmax) {
    166 				DPRINTF(("%s: warnmax exists\n", __func__));
    167 				error = EEXIST;
    168 				props &= ~(PROP_WARNMAX | PROP_BATTHIGH);
    169 			}
    170 		}
    171 		if (props & edata->upropset & (PROP_WARNMIN | PROP_BATTWARN)) {
    172 			if (lims->sel_warnmin == edata->limits.sel_warnmin) {
    173 				DPRINTF(("%s: warnmin exists\n", __func__));
    174 				error = EEXIST;
    175 				props &= ~(PROP_WARNMIN | PROP_BATTWARN);
    176 			}
    177 		}
    178 		if (props & edata->upropset & (PROP_CRITMIN | PROP_BATTCAP)) {
    179 			if (lims->sel_critmin == edata->limits.sel_critmin) {
    180 				DPRINTF(("%s: critmin exists\n", __func__));
    181 				error = EEXIST;
    182 				props &= ~(PROP_CRITMIN | PROP_BATTCAP);
    183 			}
    184 		}
    185 		if (props && see->see_type == PENVSYS_EVENT_NULL)
    186 			see->see_type = crittype;
    187 
    188 		break;
    189 	}
    190 	if (crittype == PENVSYS_EVENT_NULL && see != NULL) {
    191 		mutex_exit(&sme->sme_mtx);
    192 		return EEXIST;
    193 	}
    194 
    195 	if (see == NULL) {
    196 		/*
    197 		 * New event requested - allocate a sysmon_envsys event.
    198 		 */
    199 		see = kmem_zalloc(sizeof(*see), KM_SLEEP);
    200 		if (see == NULL)
    201 			return ENOMEM;
    202 
    203 		DPRINTF(("%s: dev %s sensor %s: new event\n",
    204 		    __func__, sme->sme_name, edata->desc));
    205 
    206 		see->see_type = crittype;
    207 		see->see_sme = sme;
    208 		see->see_edata = edata;
    209 
    210 		/* Initialize sensor type and previously-sent state */
    211 
    212 		see->see_pes.pes_type = powertype;
    213 
    214 		switch (crittype) {
    215 		case PENVSYS_EVENT_CAPACITY:
    216 			see->see_evstate = ENVSYS_BATTERY_CAPACITY_NORMAL;
    217 			break;
    218 		case PENVSYS_EVENT_STATE_CHANGED:
    219 			if (edata->units == ENVSYS_BATTERY_CAPACITY)
    220 				see->see_evstate =
    221 				    ENVSYS_BATTERY_CAPACITY_NORMAL;
    222 			else if (edata->units == ENVSYS_DRIVE)
    223 				see->see_evstate = ENVSYS_DRIVE_EMPTY;
    224 			else if (edata->units == ENVSYS_INDICATOR)
    225 				see->see_evstate = ENVSYS_SVALID;
    226 			else
    227 				panic("%s: bad units for "
    228 				      "PENVSYS_EVENT_STATE_CHANGED", __func__);
    229 			break;
    230 		case PENVSYS_EVENT_CRITICAL:
    231 		case PENVSYS_EVENT_LIMITS:
    232 		default:
    233 			see->see_evstate = ENVSYS_SVALID;
    234 			break;
    235 		}
    236 		see->see_evvalue = 0;
    237 
    238 		(void)strlcpy(see->see_pes.pes_dvname, sme->sme_name,
    239 		    sizeof(see->see_pes.pes_dvname));
    240 		(void)strlcpy(see->see_pes.pes_sensname, edata->desc,
    241 		    sizeof(see->see_pes.pes_sensname));
    242 	}
    243 
    244 	/*
    245 	 * Limit operation requested.
    246 	 */
    247 #define	LIMIT_OP(k, l, p)						\
    248 	if (props & p) {						\
    249 		objkey = k;						\
    250 		obj = prop_dictionary_get(sdict, objkey);		\
    251 		if (obj != NULL &&					\
    252 		    prop_object_type(obj) != PROP_TYPE_NUMBER) {	\
    253 			DPRINTF(("%s: (%s) %s object no TYPE_NUMBER\n",	\
    254 			    __func__, sme->sme_name, objkey));		\
    255 			error = ENOTSUP;				\
    256 		} else {						\
    257 			edata->limits.l = lims->l;			\
    258 			error = sme_sensor_upint32(sdict, objkey,lims->l); \
    259 			DPRINTF(("%s: (%s) event [sensor=%s type=%d] "	\
    260 			    "(%s updated)\n", __func__, sme->sme_name,	\
    261 			    edata->desc, crittype, objkey));		\
    262 		}							\
    263 		if (error && error != EEXIST)				\
    264 			goto out;					\
    265 		edata->upropset |= p;					\
    266 	}
    267 
    268 	/* Value-based limits */
    269 	LIMIT_OP("critical-max", sel_critmax, PROP_CRITMAX);
    270 	LIMIT_OP("warning-max",  sel_warnmax, PROP_WARNMAX);
    271 	LIMIT_OP("warning-min",  sel_warnmin, PROP_WARNMIN);
    272 	LIMIT_OP("critical-min", sel_critmin, PROP_CRITMIN);
    273 
    274 	/* %Capacity-based limits */
    275 	LIMIT_OP("maximum-capacity",  sel_critmax,  PROP_BATTMAX);
    276 	LIMIT_OP("high-capacity",     sel_warnmax,  PROP_BATTHIGH);
    277 	LIMIT_OP("warning-capacity",  sel_warnmin,  PROP_BATTWARN);
    278 	LIMIT_OP("critical-capacity", sel_critmin,  PROP_BATTCAP);
    279 
    280 #undef LIMIT_OP
    281 
    282 	if (props & PROP_DRIVER_LIMITS)
    283 		edata->upropset |= PROP_DRIVER_LIMITS;
    284 	else
    285 		edata->upropset &= ~PROP_DRIVER_LIMITS;
    286 
    287 	DPRINTF(("%s: (%s) event registered (sensor=%s snum=%d type=%d "
    288 	    "critmin=%" PRIu32 " warnmin=%" PRIu32 " warnmax=%" PRIu32
    289 	    " critmax=%" PRIu32 " props 0x%04x)\n", __func__,
    290 	    see->see_sme->sme_name, see->see_pes.pes_sensname,
    291 	    edata->sensor, see->see_type, edata->limits.sel_critmin,
    292 	    edata->limits.sel_warnmin, edata->limits.sel_warnmax,
    293 	    edata->limits.sel_critmax, edata->upropset));
    294 	/*
    295 	 * Initialize the events framework if it wasn't initialized before.
    296 	 */
    297 	if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0)
    298 		error = sme_events_init(sme);
    299 
    300 	/*
    301 	 * If driver requested notification, advise it of new
    302 	 * limit values
    303 	 */
    304 	if (sme->sme_set_limits)
    305 		(*sme->sme_set_limits)(sme, edata, &(edata->limits),
    306 					&(edata->upropset));
    307 
    308 out:
    309 	if ((error == 0 || error == EEXIST) && osee == NULL)
    310 		LIST_INSERT_HEAD(&sme->sme_events_list, see, see_list);
    311 
    312 	mutex_exit(&sme->sme_mtx);
    313 
    314 	return error;
    315 }
    316 
    317 /*
    318  * sme_event_unregister_all:
    319  *
    320  * 	+ Unregisters all events associated with a sysmon envsys device.
    321  */
    322 void
    323 sme_event_unregister_all(struct sysmon_envsys *sme)
    324 {
    325 	sme_event_t *see;
    326 	int evcounter = 0;
    327 
    328 	KASSERT(sme != NULL);
    329 
    330 	mutex_enter(&sme->sme_mtx);
    331 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    332 		while (see->see_flags & SEE_EVENT_WORKING)
    333 			cv_wait(&sme->sme_condvar, &sme->sme_mtx);
    334 
    335 		if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0)
    336 			evcounter++;
    337 	}
    338 
    339 	DPRINTF(("%s: total events %d (%s)\n", __func__,
    340 	    evcounter, sme->sme_name));
    341 
    342 	while ((see = LIST_FIRST(&sme->sme_events_list))) {
    343 		if (evcounter == 0)
    344 			break;
    345 
    346 		if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0) {
    347 			DPRINTF(("%s: event %s %d removed (%s)\n", __func__,
    348 			    see->see_pes.pes_sensname, see->see_type,
    349 			    sme->sme_name));
    350 			sme_remove_event(see, sme);
    351 
    352 			evcounter--;
    353 		}
    354 	}
    355 
    356 	if (LIST_EMPTY(&sme->sme_events_list))
    357 		if (sme->sme_flags & SME_CALLOUT_INITIALIZED)
    358 			sme_events_destroy(sme);
    359 	mutex_exit(&sme->sme_mtx);
    360 }
    361 
    362 /*
    363  * sme_event_unregister:
    364  *
    365  * 	+ Unregisters an event from the specified sysmon envsys device.
    366  */
    367 int
    368 sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type)
    369 {
    370 	sme_event_t *see;
    371 	bool found = false;
    372 
    373 	KASSERT(sensor != NULL);
    374 
    375 	mutex_enter(&sme->sme_mtx);
    376 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    377 		if (strcmp(see->see_pes.pes_sensname, sensor) == 0) {
    378 			if (see->see_type == type) {
    379 				found = true;
    380 				break;
    381 			}
    382 		}
    383 	}
    384 
    385 	if (!found) {
    386 		mutex_exit(&sme->sme_mtx);
    387 		return EINVAL;
    388 	}
    389 
    390 	/*
    391 	 * Wait for the event to finish its work, remove from the list
    392 	 * and release resouces.
    393 	 */
    394 	while (see->see_flags & SEE_EVENT_WORKING)
    395 		cv_wait(&sme->sme_condvar, &sme->sme_mtx);
    396 
    397 	DPRINTF(("%s: removed dev=%s sensor=%s type=%d\n",
    398 	    __func__, see->see_pes.pes_dvname, sensor, type));
    399 
    400 	sme_remove_event(see, sme);
    401 
    402 	mutex_exit(&sme->sme_mtx);
    403 	return 0;
    404 }
    405 
    406 /*
    407  * sme_event_unregister_sensor:
    408  *
    409  *	+ Unregisters any event associated with a specific sensor
    410  *	  The caller must already own the sme_mtx.
    411  */
    412 int
    413 sme_event_unregister_sensor(struct sysmon_envsys *sme, envsys_data_t *edata)
    414 {
    415 	sme_event_t *see;
    416 	bool found = false;
    417 
    418 	KASSERT(mutex_owned(&sme->sme_mtx));
    419 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    420 		if (see->see_edata == edata) {
    421 			found = true;
    422 			break;
    423 		}
    424 	}
    425 	if (!found)
    426 		return EINVAL;
    427 
    428 	/*
    429 	 * Wait for the event to finish its work, remove from the list
    430 	 * and release resouces.
    431 	 */
    432 	while (see->see_flags & SEE_EVENT_WORKING)
    433 		cv_wait(&sme->sme_condvar, &sme->sme_mtx);
    434 
    435 	DPRINTF(("%s: removed dev=%s sensor=%s\n",
    436 	    __func__, see->see_pes.pes_dvname, edata->desc));
    437 
    438 	sme_remove_event(see, sme);
    439 
    440 	return 0;
    441 }
    442 
    443 static void
    444 sme_remove_event(sme_event_t *see, struct sysmon_envsys *sme)
    445 {
    446 
    447 	KASSERT(mutex_owned(&sme->sme_mtx));
    448 
    449 	if (see->see_edata->flags & ENVSYS_FHAS_ENTROPY)
    450 		rnd_detach_source(&see->see_edata->rnd_src);
    451 	LIST_REMOVE(see, see_list);
    452 	/*
    453 	 * So the events list is empty, we'll do the following:
    454 	 *
    455 	 * 	- stop and destroy the callout.
    456 	 * 	- destroy the workqueue.
    457 	 */
    458 	if (LIST_EMPTY(&sme->sme_events_list))
    459 		sme_events_destroy(sme);
    460 
    461 	kmem_free(see, sizeof(*see));
    462 }
    463 
    464 /*
    465  * sme_event_drvadd:
    466  *
    467  * 	+ Registers a new event for a device that had enabled any of
    468  * 	  the monitoring flags in the driver.
    469  */
    470 void
    471 sme_event_drvadd(void *arg)
    472 {
    473 	sme_event_drv_t *sed_t = arg;
    474 	sysmon_envsys_lim_t lims;
    475 	uint32_t props;
    476 	int error = 0;
    477 
    478 	KASSERT(sed_t != NULL);
    479 
    480 #define SEE_REGEVENT(a, b, c)						\
    481 do {									\
    482 	if (sed_t->sed_edata->flags & (a)) {				\
    483 		char str[ENVSYS_DESCLEN] = "monitoring-state-";		\
    484 									\
    485 		error = sme_event_register(sed_t->sed_sdict,		\
    486 				      sed_t->sed_edata,			\
    487 				      sed_t->sed_sme,			\
    488 				      &lims, props,			\
    489 				      (b),				\
    490 				      sed_t->sed_powertype);		\
    491 		if (error && error != EEXIST)				\
    492 			printf("%s: failed to add event! "		\
    493 			    "error=%d sensor=%s event=%s\n",		\
    494 			    __func__, error,				\
    495 			    sed_t->sed_edata->desc, (c));		\
    496 		else {							\
    497 			(void)strlcat(str, (c), sizeof(str));		\
    498 			prop_dictionary_set_bool(sed_t->sed_sdict,	\
    499 						 str,			\
    500 						 true);			\
    501 		}							\
    502 	}								\
    503 } while (/* CONSTCOND */ 0)
    504 
    505 	/*
    506 	 * If driver provides a method to retrieve its internal limit
    507 	 * values, call it and use those returned values as initial
    508 	 * limits for event monitoring.
    509 	 */
    510 	props = 0;
    511 	if (sed_t->sed_edata->flags & ENVSYS_FMONLIMITS)
    512 		if (sed_t->sed_sme->sme_get_limits)
    513 			(*sed_t->sed_sme->sme_get_limits)(sed_t->sed_sme,
    514 							  sed_t->sed_edata,
    515 							  &lims, &props);
    516 	/*
    517 	 * If driver doesn't provide a way to "absorb" user-specified
    518 	 * limit values, we must monitor all limits ourselves
    519 	 */
    520 	if (sed_t->sed_sme->sme_set_limits == NULL)
    521 		props &= ~PROP_DRIVER_LIMITS;
    522 
    523 	/* Register the events that were specified */
    524 
    525 	SEE_REGEVENT(ENVSYS_FMONCRITICAL,
    526 		     PENVSYS_EVENT_CRITICAL,
    527 		     "critical");
    528 
    529 	SEE_REGEVENT(ENVSYS_FMONSTCHANGED,
    530 		     PENVSYS_EVENT_STATE_CHANGED,
    531 		     "state-changed");
    532 
    533 	SEE_REGEVENT(ENVSYS_FMONLIMITS,
    534 		     PENVSYS_EVENT_LIMITS,
    535 		     "hw-range-limits");
    536 
    537 	SEE_REGEVENT(ENVSYS_FHAS_ENTROPY,
    538 		     PENVSYS_EVENT_NULL,
    539 		     "refresh-event");
    540 
    541 	/*
    542 	 * we are done, free memory now.
    543 	 */
    544 	kmem_free(sed_t, sizeof(*sed_t));
    545 }
    546 
    547 /*
    548  * sme_events_init:
    549  *
    550  * 	+ Initialize the events framework for this device.
    551  */
    552 int
    553 sme_events_init(struct sysmon_envsys *sme)
    554 {
    555 	int error = 0;
    556 
    557 	KASSERT(sme != NULL);
    558 	KASSERT(mutex_owned(&sme->sme_mtx));
    559 
    560 	error = workqueue_create(&sme->sme_wq, sme->sme_name,
    561 	    sme_events_worker, sme, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE);
    562 	if (error)
    563 		return error;
    564 
    565 	mutex_init(&sme->sme_callout_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
    566 	callout_init(&sme->sme_callout, CALLOUT_MPSAFE);
    567 	callout_setfunc(&sme->sme_callout, sme_events_check, sme);
    568 	sme->sme_flags |= SME_CALLOUT_INITIALIZED;
    569 	sme_schedule_callout(sme);
    570 	DPRINTF(("%s: events framework initialized for '%s'\n",
    571 	    __func__, sme->sme_name));
    572 
    573 	return error;
    574 }
    575 
    576 /*
    577  * sme_schedule_callout
    578  *
    579  *	(Re)-schedule the device's callout timer
    580  */
    581 void
    582 sme_schedule_callout(struct sysmon_envsys *sme)
    583 {
    584 	uint64_t timo;
    585 
    586 	KASSERT(sme != NULL);
    587 
    588 	if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0)
    589 		return;
    590 
    591 	if (sme->sme_events_timeout)
    592 		timo = sme->sme_events_timeout * hz;
    593 	else
    594 		timo = SME_EVTIMO;
    595 
    596 	callout_stop(&sme->sme_callout);
    597 	callout_schedule(&sme->sme_callout, timo);
    598 }
    599 
    600 /*
    601  * sme_events_destroy:
    602  *
    603  * 	+ Destroys the event framework for this device: callout
    604  * 	  stopped, workqueue destroyed and callout mutex destroyed.
    605  */
    606 void
    607 sme_events_destroy(struct sysmon_envsys *sme)
    608 {
    609 	KASSERT(mutex_owned(&sme->sme_mtx));
    610 
    611 	callout_stop(&sme->sme_callout);
    612 	workqueue_destroy(sme->sme_wq);
    613 	mutex_destroy(&sme->sme_callout_mtx);
    614 	callout_destroy(&sme->sme_callout);
    615 	sme->sme_flags &= ~SME_CALLOUT_INITIALIZED;
    616 	DPRINTF(("%s: events framework destroyed for '%s'\n",
    617 	    __func__, sme->sme_name));
    618 }
    619 
    620 /*
    621  * sysmon_envsys_update_limits
    622  *
    623  *	+ If a driver needs to update the limits that it is providing,
    624  *	  we need to update the dictionary data as well as the limits.
    625  *	  This only makes sense if the driver is capable of providing
    626  *	  its limits, and if there is a limits event-monitor.
    627  */
    628 int
    629 sysmon_envsys_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata)
    630 {
    631 	int err;
    632 
    633 	sysmon_envsys_acquire(sme, false);
    634 	if (sme->sme_get_limits == NULL ||
    635 	    (edata->flags & ENVSYS_FMONLIMITS) == 0)
    636 		err = EINVAL;
    637 	else
    638 		err = sme_update_limits(sme, edata);
    639 	sysmon_envsys_release(sme, false);
    640 
    641 	return err;
    642 }
    643 
    644 /*
    645  * sme_update_limits
    646  *
    647  *	+ Internal version of sysmon_envsys_update_limits() to be used
    648  *	  when the device has already been sysmon_envsys_acquire()d.
    649  */
    650 
    651 int
    652 sme_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata)
    653 {
    654 	prop_dictionary_t sdict = NULL;
    655 	prop_array_t array = NULL;
    656 	sysmon_envsys_lim_t lims;
    657 	sme_event_t *see;
    658 	uint32_t props = 0;
    659 
    660 	/* Find the dictionary for this sensor */
    661 	array = prop_dictionary_get(sme_propd, sme->sme_name);
    662 	if (array == NULL ||
    663 	    prop_object_type(array) != PROP_TYPE_ARRAY) {
    664 		DPRINTF(("%s: array device failed\n", __func__));
    665 		return EINVAL;
    666 	}
    667 
    668 	sdict = prop_array_get(array, edata->sensor);
    669 	if (sdict == NULL) {
    670 		return EINVAL;
    671 	}
    672 
    673 	/* Find the event definition to get its powertype */
    674 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    675 		if (edata == see->see_edata &&
    676 		    see->see_type == PENVSYS_EVENT_LIMITS)
    677 			break;
    678 	}
    679 	if (see == NULL)
    680 		return EINVAL;
    681 
    682 	/* Update limit values from driver if possible */
    683 	if (sme->sme_get_limits != NULL)
    684 		(*sme->sme_get_limits)(sme, edata, &lims, &props);
    685 
    686 	/* Update event and dictionary */
    687 	sme_event_register(sdict, edata, sme, &lims, props,
    688 			   PENVSYS_EVENT_LIMITS, see->see_pes.pes_type);
    689 
    690 	return 0;
    691 }
    692 
    693 /*
    694  * sme_events_check:
    695  *
    696  * 	+ Passes the events to the workqueue thread and stops
    697  * 	  the callout if the 'low-power' condition is triggered.
    698  */
    699 void
    700 sme_events_check(void *arg)
    701 {
    702 	struct sysmon_envsys *sme = arg;
    703 	sme_event_t *see;
    704 	uint64_t timo;
    705 
    706 	KASSERT(sme != NULL);
    707 
    708 	mutex_enter(&sme->sme_callout_mtx);
    709 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    710 		workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL);
    711 		see->see_edata->flags |= ENVSYS_FNEED_REFRESH;
    712 	}
    713 	if (sme->sme_events_timeout)
    714 		timo = sme->sme_events_timeout * hz;
    715 	else
    716 		timo = SME_EVTIMO;
    717 	if (!sysmon_low_power)
    718 		sme_schedule_callout(sme);
    719 	mutex_exit(&sme->sme_callout_mtx);
    720 }
    721 
    722 /*
    723  * sme_events_worker:
    724  *
    725  * 	+ workqueue thread that checks if there's a critical condition
    726  * 	  and sends an event if it was triggered.
    727  */
    728 void
    729 sme_events_worker(struct work *wk, void *arg)
    730 {
    731 	sme_event_t *see = (void *)wk;
    732 	struct sysmon_envsys *sme = see->see_sme;
    733 	envsys_data_t *edata = see->see_edata;
    734 
    735 	KASSERT(wk == &see->see_wk);
    736 	KASSERT(sme != NULL || edata != NULL);
    737 
    738 	mutex_enter(&sme->sme_mtx);
    739 	see->see_flags |= SEE_EVENT_WORKING;
    740 	/*
    741 	 * sme_events_check marks the sensors to make us refresh them here.
    742 	 * sme_envsys_refresh_sensor will not call the driver if the driver
    743 	 * does its own setting of the sensor value.
    744 	 */
    745 	if ((edata->flags & ENVSYS_FNEED_REFRESH) != 0) {
    746 		/* refresh sensor in device */
    747 		sysmon_envsys_refresh_sensor(sme, edata);
    748 		edata->flags &= ~ENVSYS_FNEED_REFRESH;
    749 	}
    750 
    751 	DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d type=%d state=%d units=%d "
    752 	    "value_cur=%d upropset=%d\n", __func__, sme->sme_name, edata->desc,
    753 	    edata->sensor, see->see_type, edata->state, edata->units,
    754 	    edata->value_cur, edata->upropset));
    755 
    756 	/* skip the event if current sensor is in invalid state */
    757 	if (edata->state == ENVSYS_SINVALID)
    758 		goto out;
    759 
    760 	/*
    761 	 * For range limits, if the driver claims responsibility for
    762 	 * limit/range checking, just user driver-supplied status.
    763 	 * Else calculate our own status.  Note that driver must
    764 	 * relinquish responsibility for ALL limits if there is even
    765 	 * one limit that it cannot handle!
    766 	 *
    767 	 * If this is a CAPACITY monitor, but the sensor's max_value
    768 	 * is not set, treat it as though the monitor does not exist.
    769 	 */
    770 	if ((see->see_type == PENVSYS_EVENT_LIMITS ||
    771 	     see->see_type == PENVSYS_EVENT_CAPACITY) &&
    772 	    (edata->upropset & PROP_DRIVER_LIMITS) == 0) {
    773 		if ((see->see_type == PENVSYS_EVENT_CAPACITY) &&
    774 		    (edata->value_max == 0))
    775 			edata->state = ENVSYS_SVALID;
    776 		else if ((edata->upropset & (PROP_CRITMIN | PROP_BATTCAP)) &&
    777 		    (edata->value_cur < edata->limits.sel_critmin))
    778 			edata->state = ENVSYS_SCRITUNDER;
    779 		else if ((edata->upropset & (PROP_WARNMIN | PROP_BATTWARN)) &&
    780 			 (edata->value_cur < edata->limits.sel_warnmin))
    781 			edata->state = ENVSYS_SWARNUNDER;
    782 		else if ((edata->upropset & (PROP_CRITMAX | PROP_BATTMAX)) &&
    783 			 (edata->value_cur > edata->limits.sel_critmax))
    784 			edata->state = ENVSYS_SCRITOVER;
    785 		else if ((edata->upropset & (PROP_WARNMAX | PROP_BATTHIGH)) &&
    786 			 (edata->value_cur > edata->limits.sel_warnmax))
    787 			edata->state = ENVSYS_SWARNOVER;
    788 		else
    789 			edata->state = ENVSYS_SVALID;
    790 	}
    791 	sme_deliver_event(see);
    792 
    793 out:
    794 	see->see_flags &= ~SEE_EVENT_WORKING;
    795 	cv_broadcast(&sme->sme_condvar);
    796 	mutex_exit(&sme->sme_mtx);
    797 }
    798 
    799 /*
    800  * sysmon_envsys_sensor_event
    801  *
    802  *	+ Find the monitor event of a particular type for a given sensor
    803  *	  on a device and deliver the event if one is required.  If
    804  *	  no event type is specified, deliver all events for the sensor.
    805  */
    806 void
    807 sysmon_envsys_sensor_event(struct sysmon_envsys *sme, envsys_data_t *edata,
    808 			   int ev_type)
    809 {
    810 	sme_event_t *see;
    811 
    812 	mutex_enter(&sme->sme_mtx);
    813 	LIST_FOREACH(see, &sme->sme_events_list, see_list) {
    814 		if (edata != see->see_edata)
    815 			continue;
    816 		if (ev_type == 0 ||
    817 		    ev_type == see->see_type) {
    818 			sme_deliver_event(see);
    819 			if (ev_type != 0)
    820 				break;
    821 		}
    822 	}
    823 	mutex_exit(&sme->sme_mtx);
    824 }
    825 
    826 /*
    827  * sme_deliver_event:
    828  *
    829  * 	+ If new sensor state requires it, send an event to powerd
    830  *
    831  *	  Must be called with the device's sysmon mutex held
    832  *		see->see_sme->sme_mtx
    833  */
    834 void
    835 sme_deliver_event(sme_event_t *see)
    836 {
    837 	envsys_data_t *edata = see->see_edata;
    838 	const struct sme_descr_entry *sdt = NULL;
    839 	const struct sme_sensor_event *sse = sme_sensor_event;
    840 	int i, state = 0;
    841 
    842 	switch (see->see_type) {
    843 	case PENVSYS_EVENT_LIMITS:
    844 	case PENVSYS_EVENT_CAPACITY:
    845 		/*
    846 		 * Send event if state has changed
    847 		 */
    848 		if (edata->state == see->see_evstate)
    849 			break;
    850 
    851 		for (i = 0; sse[i].state != -1; i++)
    852 			if (sse[i].state == edata->state)
    853 				break;
    854 
    855 		if (sse[i].state == -1)
    856 			break;
    857 
    858 		if (edata->state == ENVSYS_SVALID)
    859 			sysmon_penvsys_event(&see->see_pes,
    860 					     PENVSYS_EVENT_NORMAL);
    861 		else
    862 			sysmon_penvsys_event(&see->see_pes, sse[i].event);
    863 
    864 		see->see_evstate = edata->state;
    865 		DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d state=%d send_ev=%d\n",
    866 		    __func__, see->see_sme->sme_name, edata->desc,
    867 		    edata->sensor, edata->state,
    868 		    (edata->state == ENVSYS_SVALID) ? PENVSYS_EVENT_NORMAL :
    869 			sse[i].event));
    870 
    871 		break;
    872 
    873 	/*
    874 	 * Send PENVSYS_EVENT_CRITICAL event if:
    875 	 *	State has gone from non-CRITICAL to CRITICAL,
    876 	 *	State remains CRITICAL and value has changed, or
    877 	 *	State has returned from CRITICAL to non-CRITICAL
    878 	 */
    879 	case PENVSYS_EVENT_CRITICAL:
    880 		DPRINTF(("%s: CRITICAL: old/new state %d/%d, old/new value "
    881 		    "%d/%d\n", __func__, see->see_evstate, edata->state,
    882 		    see->see_evvalue, edata->value_cur));
    883 		if (edata->state == ENVSYS_SVALID &&
    884 		    see->see_evstate != ENVSYS_SVALID) {
    885 			sysmon_penvsys_event(&see->see_pes,
    886 					     PENVSYS_EVENT_NORMAL);
    887 			see->see_evstate = ENVSYS_SVALID;
    888 			break;
    889 		} else if (edata->state != ENVSYS_SCRITICAL)
    890 			break;
    891 		if (see->see_evstate != ENVSYS_SCRITICAL ||
    892 		    see->see_evvalue != edata->value_cur) {
    893 			sysmon_penvsys_event(&see->see_pes,
    894 					     PENVSYS_EVENT_CRITICAL);
    895 			see->see_evstate = ENVSYS_SCRITICAL;
    896 		}
    897 		see->see_evvalue = edata->value_cur;
    898 		break;
    899 
    900 	/*
    901 	 * if value_cur is not normal (battery) or online (drive),
    902 	 * send the event...
    903 	 */
    904 	case PENVSYS_EVENT_STATE_CHANGED:
    905 		/*
    906 		 * the state has not been changed, just ignore the event.
    907 		 */
    908 		if (edata->value_cur == see->see_evvalue)
    909 			break;
    910 
    911 		switch (edata->units) {
    912 		case ENVSYS_DRIVE:
    913 			sdt = sme_find_table_entry(SME_DESC_DRIVE_STATES,
    914 			    edata->value_cur);
    915 			state = ENVSYS_DRIVE_ONLINE;
    916 			break;
    917 		case ENVSYS_BATTERY_CAPACITY:
    918 			sdt = sme_find_table_entry(SME_DESC_BATTERY_CAPACITY,
    919 			    edata->value_cur);
    920 			state = ENVSYS_BATTERY_CAPACITY_NORMAL;
    921 			break;
    922 		case ENVSYS_INDICATOR:
    923 			sdt = sme_find_table_entry(SME_DESC_INDICATOR,
    924 			    edata->value_cur);
    925 			state = see->see_evvalue;	/* force state change */
    926 			break;
    927 		default:
    928 			panic("%s: bad units for PENVSYS_EVENT_STATE_CHANGED",
    929 			    __func__);
    930 		}
    931 
    932 		if (sdt->type == -1)
    933 			break;
    934 
    935 		/*
    936 		 * copy current state description.
    937 		 */
    938 		(void)strlcpy(see->see_pes.pes_statedesc, sdt->desc,
    939 		    sizeof(see->see_pes.pes_statedesc));
    940 
    941 		if (edata->value_cur == state)
    942 			/*
    943 			 * state returned to normal condition
    944 			 */
    945 			sysmon_penvsys_event(&see->see_pes,
    946 					     PENVSYS_EVENT_NORMAL);
    947 		else
    948 			/*
    949 			 * state changed to abnormal condition
    950 			 */
    951 			sysmon_penvsys_event(&see->see_pes, see->see_type);
    952 
    953 		see->see_evvalue = edata->value_cur;
    954 
    955 		/*
    956 		 * There's no need to continue if it's a drive sensor.
    957 		 */
    958 		if (edata->units == ENVSYS_DRIVE)
    959 			break;
    960 
    961 		/*
    962 		 * Check if the system is running in low power and send the
    963 		 * event to powerd (if running) or shutdown the system
    964 		 * otherwise.
    965 		 */
    966 		if (!sysmon_low_power && sme_event_check_low_power()) {
    967 			struct penvsys_state pes;
    968 
    969 			/*
    970 			 * Stop the callout and send the 'low-power' event.
    971 			 */
    972 			sysmon_low_power = true;
    973 			callout_stop(&see->see_sme->sme_callout);
    974 			pes.pes_type = PENVSYS_TYPE_BATTERY;
    975 			sysmon_penvsys_event(&pes, PENVSYS_EVENT_LOW_POWER);
    976 		}
    977 		break;
    978 	case PENVSYS_EVENT_NULL:
    979 		break;
    980 	default:
    981 		panic("%s: invalid event type %d", __func__, see->see_type);
    982 	}
    983 }
    984 
    985 /*
    986  * Returns true if the system is in low power state: an AC adapter
    987  * is OFF and all batteries are in LOW/CRITICAL state.
    988  */
    989 static bool
    990 sme_event_check_low_power(void)
    991 {
    992 	if (!sme_acadapter_check())
    993 		return false;
    994 
    995 	return sme_battery_check();
    996 }
    997 
    998 /*
    999  * Called with the sysmon_envsys device mtx held through the
   1000  * workqueue thread.
   1001  */
   1002 static bool
   1003 sme_acadapter_check(void)
   1004 {
   1005 	struct sysmon_envsys *sme;
   1006 	envsys_data_t *edata;
   1007 	bool dev = false, sensor = false;
   1008 
   1009 	LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
   1010 		if (sme->sme_class == SME_CLASS_ACADAPTER) {
   1011 			dev = true;
   1012 			break;
   1013 		}
   1014 	}
   1015 
   1016 	/*
   1017 	 * No AC Adapter devices were found.
   1018 	 */
   1019 	if (!dev)
   1020 		return false;
   1021 
   1022 	/*
   1023 	 * Check if there's an AC adapter device connected.
   1024 	 */
   1025 	TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1026 		if (edata->units == ENVSYS_INDICATOR) {
   1027 			sensor = true;
   1028 			/* refresh current sensor */
   1029 			sysmon_envsys_refresh_sensor(sme, edata);
   1030 			if (edata->value_cur)
   1031 				return false;
   1032 		}
   1033 	}
   1034 
   1035 	if (!sensor)
   1036 		return false;
   1037 
   1038 	/*
   1039 	 * AC adapter found and not connected.
   1040 	 */
   1041 	return true;
   1042 }
   1043 
   1044 /*
   1045  * Called with the sysmon_envsys device mtx held through the
   1046  * workqueue thread.
   1047  */
   1048 static bool
   1049 sme_battery_check(void)
   1050 {
   1051 	struct sysmon_envsys *sme;
   1052 	envsys_data_t *edata;
   1053 	int batteriesfound = 0;
   1054 	bool present, batterycap, batterycharge;
   1055 
   1056 	/*
   1057 	 * Check for battery devices and its state.
   1058 	 */
   1059 	LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
   1060 		if (sme->sme_class != SME_CLASS_BATTERY)
   1061 			continue;
   1062 
   1063 		present = true;
   1064 		TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1065 			if (edata->units == ENVSYS_INDICATOR &&
   1066 			    !edata->value_cur) {
   1067 				present = false;
   1068 				break;
   1069 			}
   1070 		}
   1071 		if (!present)
   1072 			continue;
   1073 		/*
   1074 		 * We've found a battery device...
   1075 		 */
   1076 		batteriesfound++;
   1077 		batterycap = batterycharge = false;
   1078 		TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1079 			if (edata->units == ENVSYS_BATTERY_CAPACITY) {
   1080 				batterycap = true;
   1081 				if (!sme_battery_critical(edata))
   1082 					return false;
   1083 			} else if (edata->units == ENVSYS_BATTERY_CHARGE) {
   1084 				batterycharge = true;
   1085 				if (edata->value_cur)
   1086 					return false;
   1087 			}
   1088 		}
   1089 		if (!batterycap || !batterycharge)
   1090 			return false;
   1091 	}
   1092 
   1093 	if (!batteriesfound)
   1094 		return false;
   1095 
   1096 	/*
   1097 	 * All batteries in low/critical capacity and discharging.
   1098 	 */
   1099 	return true;
   1100 }
   1101 
   1102 static bool
   1103 sme_battery_critical(envsys_data_t *edata)
   1104 {
   1105 	if (edata->value_cur == ENVSYS_BATTERY_CAPACITY_CRITICAL ||
   1106 	    edata->value_cur == ENVSYS_BATTERY_CAPACITY_LOW)
   1107 		return true;
   1108 
   1109 	return false;
   1110 }
   1111