Home | History | Annotate | Line # | Download | only in sysmon
sysmon_envsys.c revision 1.87
      1 /*	$NetBSD: sysmon_envsys.c,v 1.87 2009/06/08 00:55:35 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  * Copyright (c) 2000 Zembu Labs, Inc.
     30  * All rights reserved.
     31  *
     32  * Author: Jason R. Thorpe <thorpej (at) zembu.com>
     33  *
     34  * Redistribution and use in source and binary forms, with or without
     35  * modification, are permitted provided that the following conditions
     36  * are met:
     37  * 1. Redistributions of source code must retain the above copyright
     38  *    notice, this list of conditions and the following disclaimer.
     39  * 2. Redistributions in binary form must reproduce the above copyright
     40  *    notice, this list of conditions and the following disclaimer in the
     41  *    documentation and/or other materials provided with the distribution.
     42  * 3. All advertising materials mentioning features or use of this software
     43  *    must display the following acknowledgement:
     44  *	This product includes software developed by Zembu Labs, Inc.
     45  * 4. Neither the name of Zembu Labs nor the names of its employees may
     46  *    be used to endorse or promote products derived from this software
     47  *    without specific prior written permission.
     48  *
     49  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
     50  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
     51  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
     52  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
     53  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     54  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     55  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     56  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     57  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     58  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     59  */
     60 
     61 /*
     62  * Environmental sensor framework for sysmon, exported to userland
     63  * with proplib(3).
     64  */
     65 
     66 #include <sys/cdefs.h>
     67 __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.87 2009/06/08 00:55:35 pgoyette Exp $");
     68 
     69 #include <sys/param.h>
     70 #include <sys/types.h>
     71 #include <sys/conf.h>
     72 #include <sys/errno.h>
     73 #include <sys/fcntl.h>
     74 #include <sys/kernel.h>
     75 #include <sys/systm.h>
     76 #include <sys/proc.h>
     77 #include <sys/mutex.h>
     78 #include <sys/kmem.h>
     79 
     80 /* #define ENVSYS_DEBUG */
     81 #include <dev/sysmon/sysmonvar.h>
     82 #include <dev/sysmon/sysmon_envsysvar.h>
     83 #include <dev/sysmon/sysmon_taskq.h>
     84 
     85 kmutex_t sme_global_mtx;
     86 
     87 static prop_dictionary_t sme_propd;
     88 static uint32_t sysmon_envsys_next_sensor_index;
     89 static struct sysmon_envsys *sysmon_envsys_find_40(u_int);
     90 
     91 static void sysmon_envsys_destroy_plist(prop_array_t);
     92 static void sme_remove_userprops(void);
     93 static int sme_add_property_dictionary(struct sysmon_envsys *, prop_array_t,
     94 				       prop_dictionary_t);
     95 static void sme_initial_refresh(void *);
     96 
     97 /*
     98  * sysmon_envsys_init:
     99  *
    100  * 	+ Initialize global mutex, dictionary and the linked list.
    101  */
    102 void
    103 sysmon_envsys_init(void)
    104 {
    105 	LIST_INIT(&sysmon_envsys_list);
    106 	mutex_init(&sme_global_mtx, MUTEX_DEFAULT, IPL_NONE);
    107 	sme_propd = prop_dictionary_create();
    108 }
    109 
    110 /*
    111  * sysmonopen_envsys:
    112  *
    113  *	+ Open the system monitor device.
    114  */
    115 int
    116 sysmonopen_envsys(dev_t dev, int flag, int mode, struct lwp *l)
    117 {
    118 	return 0;
    119 }
    120 
    121 /*
    122  * sysmonclose_envsys:
    123  *
    124  *	+ Close the system monitor device.
    125  */
    126 int
    127 sysmonclose_envsys(dev_t dev, int flag, int mode, struct lwp *l)
    128 {
    129 	return 0;
    130 }
    131 
    132 /*
    133  * sysmonioctl_envsys:
    134  *
    135  *	+ Perform a sysmon envsys control request.
    136  */
    137 int
    138 sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    139 {
    140 	struct sysmon_envsys *sme = NULL;
    141 	int error = 0;
    142 	u_int oidx;
    143 
    144 	switch (cmd) {
    145 	/*
    146 	 * To update the global dictionary with latest data from devices.
    147 	 */
    148 	case ENVSYS_GETDICTIONARY:
    149 	    {
    150 		struct plistref *plist = (struct plistref *)data;
    151 
    152 		/*
    153 		 * Update dictionaries on all sysmon envsys devices
    154 		 * registered.
    155 		 */
    156 		mutex_enter(&sme_global_mtx);
    157 		LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
    158 			sysmon_envsys_acquire(sme, false);
    159 			error = sme_update_dictionary(sme);
    160 			if (error) {
    161 				DPRINTF(("%s: sme_update_dictionary, "
    162 				    "error=%d\n", __func__, error));
    163 				sysmon_envsys_release(sme, false);
    164 				mutex_exit(&sme_global_mtx);
    165 				return error;
    166 			}
    167 			sysmon_envsys_release(sme, false);
    168 		}
    169 		mutex_exit(&sme_global_mtx);
    170 		/*
    171 		 * Copy global dictionary to userland.
    172 		 */
    173 		error = prop_dictionary_copyout_ioctl(plist, cmd, sme_propd);
    174 		break;
    175 	    }
    176 	/*
    177 	 * To set properties on multiple devices.
    178 	 */
    179 	case ENVSYS_SETDICTIONARY:
    180 	    {
    181 		const struct plistref *plist = (const struct plistref *)data;
    182 		prop_dictionary_t udict;
    183 		prop_object_iterator_t iter, iter2;
    184 		prop_object_t obj, obj2;
    185 		prop_array_t array_u, array_k;
    186 		const char *devname = NULL;
    187 
    188 		if ((flag & FWRITE) == 0)
    189 			return EPERM;
    190 
    191 		/*
    192 		 * Get dictionary from userland.
    193 		 */
    194 		error = prop_dictionary_copyin_ioctl(plist, cmd, &udict);
    195 		if (error) {
    196 			DPRINTF(("%s: copyin_ioctl error=%d\n",
    197 			    __func__, error));
    198 			break;
    199 		}
    200 
    201 		iter = prop_dictionary_iterator(udict);
    202 		if (!iter) {
    203 			prop_object_release(udict);
    204 			return ENOMEM;
    205 		}
    206 
    207 		/*
    208 		 * Iterate over the userland dictionary and process
    209 		 * the list of devices.
    210 		 */
    211 		while ((obj = prop_object_iterator_next(iter))) {
    212 			array_u = prop_dictionary_get_keysym(udict, obj);
    213 			if (prop_object_type(array_u) != PROP_TYPE_ARRAY) {
    214 				prop_object_iterator_release(iter);
    215 				prop_object_release(udict);
    216 				return EINVAL;
    217 			}
    218 
    219 			devname = prop_dictionary_keysym_cstring_nocopy(obj);
    220 			DPRINTF(("%s: processing the '%s' array requests\n",
    221 			    __func__, devname));
    222 
    223 			/*
    224 			 * find the correct sme device.
    225 			 */
    226 			sme = sysmon_envsys_find(devname);
    227 			if (!sme) {
    228 				DPRINTF(("%s: NULL sme\n", __func__));
    229 				prop_object_iterator_release(iter);
    230 				prop_object_release(udict);
    231 				return EINVAL;
    232 			}
    233 
    234 			/*
    235 			 * Find the correct array object with the string
    236 			 * supplied by the userland dictionary.
    237 			 */
    238 			array_k = prop_dictionary_get(sme_propd, devname);
    239 			if (prop_object_type(array_k) != PROP_TYPE_ARRAY) {
    240 				DPRINTF(("%s: array device failed\n",
    241 				    __func__));
    242 				sysmon_envsys_release(sme, false);
    243 				prop_object_iterator_release(iter);
    244 				prop_object_release(udict);
    245 				return EINVAL;
    246 			}
    247 
    248 			iter2 = prop_array_iterator(array_u);
    249 			if (!iter2) {
    250 				sysmon_envsys_release(sme, false);
    251 				prop_object_iterator_release(iter);
    252 				prop_object_release(udict);
    253 				return ENOMEM;
    254 			}
    255 
    256 			/*
    257 			 * Iterate over the array of dictionaries to
    258 			 * process the list of sensors and properties.
    259 			 */
    260 			while ((obj2 = prop_object_iterator_next(iter2))) {
    261 				/*
    262 				 * do the real work now.
    263 				 */
    264 				error = sme_userset_dictionary(sme,
    265 							       obj2,
    266 							       array_k);
    267 				if (error) {
    268 					sysmon_envsys_release(sme, false);
    269 					prop_object_iterator_release(iter2);
    270 					prop_object_iterator_release(iter);
    271 					prop_object_release(udict);
    272 					return error;
    273 				}
    274 			}
    275 
    276 			sysmon_envsys_release(sme, false);
    277 			prop_object_iterator_release(iter2);
    278 		}
    279 
    280 		prop_object_iterator_release(iter);
    281 		prop_object_release(udict);
    282 		break;
    283 	    }
    284 	/*
    285 	 * To remove all properties from all devices registered.
    286 	 */
    287 	case ENVSYS_REMOVEPROPS:
    288 	    {
    289 		const struct plistref *plist = (const struct plistref *)data;
    290 		prop_dictionary_t udict;
    291 		prop_object_t obj;
    292 
    293 		if ((flag & FWRITE) == 0)
    294 			return EPERM;
    295 
    296 		error = prop_dictionary_copyin_ioctl(plist, cmd, &udict);
    297 		if (error) {
    298 			DPRINTF(("%s: copyin_ioctl error=%d\n",
    299 			    __func__, error));
    300 			break;
    301 		}
    302 
    303 		obj = prop_dictionary_get(udict, "envsys-remove-props");
    304 		if (!obj || !prop_bool_true(obj)) {
    305 			DPRINTF(("%s: invalid 'envsys-remove-props'\n",
    306 			     __func__));
    307 			return EINVAL;
    308 		}
    309 
    310 		prop_object_release(udict);
    311 		sme_remove_userprops();
    312 
    313 		break;
    314 	    }
    315 	/*
    316 	 * Compatibility ioctls with the old interface, only implemented
    317 	 * ENVSYS_GTREDATA and ENVSYS_GTREINFO; enough to make old
    318 	 * applications work.
    319 	 */
    320 	case ENVSYS_GTREDATA:
    321 	    {
    322 		struct envsys_tre_data *tred = (void *)data;
    323 		envsys_data_t *edata = NULL;
    324 		bool found = false;
    325 
    326 		tred->validflags = 0;
    327 
    328 		sme = sysmon_envsys_find_40(tred->sensor);
    329 		if (!sme)
    330 			break;
    331 
    332 		oidx = tred->sensor;
    333 		tred->sensor = SME_SENSOR_IDX(sme, tred->sensor);
    334 
    335 		DPRINTFOBJ(("%s: sensor=%d oidx=%d dev=%s nsensors=%d\n",
    336 		    __func__, tred->sensor, oidx, sme->sme_name,
    337 		    sme->sme_nsensors));
    338 
    339 		TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
    340 			if (edata->sensor == tred->sensor) {
    341 				found = true;
    342 				break;
    343 			}
    344 		}
    345 
    346 		if (!found) {
    347 			sysmon_envsys_release(sme, false);
    348 			error = ENODEV;
    349 			break;
    350 		}
    351 
    352 		if (tred->sensor < sme->sme_nsensors) {
    353 			if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0 &&
    354 			    (sme->sme_flags & SME_POLL_ONLY) == 0) {
    355 				mutex_enter(&sme->sme_mtx);
    356 				(*sme->sme_refresh)(sme, edata);
    357 				mutex_exit(&sme->sme_mtx);
    358 			}
    359 
    360 			/*
    361 			 * copy required values to the old interface.
    362 			 */
    363 			tred->sensor = edata->sensor;
    364 			tred->cur.data_us = edata->value_cur;
    365 			tred->cur.data_s = edata->value_cur;
    366 			tred->max.data_us = edata->value_max;
    367 			tred->max.data_s = edata->value_max;
    368 			tred->min.data_us = edata->value_min;
    369 			tred->min.data_s = edata->value_min;
    370 			tred->avg.data_us = edata->value_avg;
    371 			tred->avg.data_s = edata->value_avg;
    372 			if (edata->units == ENVSYS_BATTERY_CHARGE)
    373 				tred->units = ENVSYS_INDICATOR;
    374 			else
    375 				tred->units = edata->units;
    376 
    377 			tred->validflags |= ENVSYS_FVALID;
    378 			tred->validflags |= ENVSYS_FCURVALID;
    379 
    380 			if (edata->flags & ENVSYS_FPERCENT) {
    381 				tred->validflags |= ENVSYS_FMAXVALID;
    382 				tred->validflags |= ENVSYS_FFRACVALID;
    383 			}
    384 
    385 			if (edata->state == ENVSYS_SINVALID) {
    386 				tred->validflags &= ~ENVSYS_FCURVALID;
    387 				tred->cur.data_us = tred->cur.data_s = 0;
    388 			}
    389 
    390 			DPRINTFOBJ(("%s: sensor=%s tred->cur.data_s=%d\n",
    391 			    __func__, edata->desc, tred->cur.data_s));
    392 			DPRINTFOBJ(("%s: tred->validflags=%d tred->units=%d"
    393 			    " tred->sensor=%d\n", __func__, tred->validflags,
    394 			    tred->units, tred->sensor));
    395 		}
    396 		tred->sensor = oidx;
    397 		sysmon_envsys_release(sme, false);
    398 
    399 		break;
    400 	    }
    401 	case ENVSYS_GTREINFO:
    402 	    {
    403 		struct envsys_basic_info *binfo = (void *)data;
    404 		envsys_data_t *edata = NULL;
    405 		bool found = false;
    406 
    407 		binfo->validflags = 0;
    408 
    409 		sme = sysmon_envsys_find_40(binfo->sensor);
    410 		if (!sme)
    411 			break;
    412 
    413 		oidx = binfo->sensor;
    414 		binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
    415 
    416 		TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
    417 			if (edata->sensor == binfo->sensor) {
    418 				found = true;
    419 				break;
    420 			}
    421 		}
    422 
    423 		if (!found) {
    424 			sysmon_envsys_release(sme, false);
    425 			error = ENODEV;
    426 			break;
    427 		}
    428 
    429 		binfo->validflags |= ENVSYS_FVALID;
    430 
    431 		if (binfo->sensor < sme->sme_nsensors) {
    432 			if (edata->units == ENVSYS_BATTERY_CHARGE)
    433 				binfo->units = ENVSYS_INDICATOR;
    434 			else
    435 				binfo->units = edata->units;
    436 
    437 			/*
    438 			 * previously, the ACPI sensor names included the
    439 			 * device name. Include that in compatibility code.
    440 			 */
    441 			if (strncmp(sme->sme_name, "acpi", 4) == 0)
    442 				(void)snprintf(binfo->desc, sizeof(binfo->desc),
    443 				    "%s %s", sme->sme_name, edata->desc);
    444 			else
    445 				(void)strlcpy(binfo->desc, edata->desc,
    446 				    sizeof(binfo->desc));
    447 		}
    448 
    449 		DPRINTFOBJ(("%s: binfo->units=%d binfo->validflags=%d\n",
    450 		    __func__, binfo->units, binfo->validflags));
    451 		DPRINTFOBJ(("%s: binfo->desc=%s binfo->sensor=%d\n",
    452 		    __func__, binfo->desc, binfo->sensor));
    453 
    454 		binfo->sensor = oidx;
    455 		sysmon_envsys_release(sme, false);
    456 
    457 		break;
    458 	    }
    459 	default:
    460 		error = ENOTTY;
    461 		break;
    462 	}
    463 
    464 	return error;
    465 }
    466 
    467 /*
    468  * sysmon_envsys_create:
    469  *
    470  * 	+ Allocates a new sysmon_envsys object and initializes the
    471  * 	  stuff for sensors and events.
    472  */
    473 struct sysmon_envsys *
    474 sysmon_envsys_create(void)
    475 {
    476 	struct sysmon_envsys *sme;
    477 
    478 	sme = kmem_zalloc(sizeof(*sme), KM_SLEEP);
    479 	TAILQ_INIT(&sme->sme_sensors_list);
    480 	LIST_INIT(&sme->sme_events_list);
    481 	mutex_init(&sme->sme_mtx, MUTEX_DEFAULT, IPL_NONE);
    482 	cv_init(&sme->sme_condvar, "sme_wait");
    483 
    484 	return sme;
    485 }
    486 
    487 /*
    488  * sysmon_envsys_destroy:
    489  *
    490  * 	+ Removes all sensors from the tail queue, destroys the callout
    491  * 	  and frees the sysmon_envsys object.
    492  */
    493 void
    494 sysmon_envsys_destroy(struct sysmon_envsys *sme)
    495 {
    496 	envsys_data_t *edata;
    497 
    498 	KASSERT(sme != NULL);
    499 
    500 	while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
    501 		edata = TAILQ_FIRST(&sme->sme_sensors_list);
    502 		TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
    503 	}
    504 	mutex_destroy(&sme->sme_mtx);
    505 	cv_destroy(&sme->sme_condvar);
    506 	kmem_free(sme, sizeof(*sme));
    507 }
    508 
    509 /*
    510  * sysmon_envsys_sensor_attach:
    511  *
    512  * 	+ Attachs a sensor into a sysmon_envsys device checking that units
    513  * 	  is set to a valid type and description is unique and not empty.
    514  */
    515 int
    516 sysmon_envsys_sensor_attach(struct sysmon_envsys *sme, envsys_data_t *edata)
    517 {
    518 	const struct sme_description_table *sdt_units;
    519 	envsys_data_t *oedata;
    520 	int i;
    521 
    522 	KASSERT(sme != NULL || edata != NULL);
    523 
    524 	/*
    525 	 * Find the correct units for this sensor.
    526 	 */
    527 	sdt_units = sme_get_description_table(SME_DESC_UNITS);
    528 	for (i = 0; sdt_units[i].type != -1; i++)
    529 		if (sdt_units[i].type == edata->units)
    530 			break;
    531 
    532 	if (strcmp(sdt_units[i].desc, "unknown") == 0)
    533 		return EINVAL;
    534 
    535 	/*
    536 	 * Check that description is not empty or duplicate.
    537 	 */
    538 	if (strlen(edata->desc) == 0)
    539 		return EINVAL;
    540 
    541 	mutex_enter(&sme->sme_mtx);
    542 	sysmon_envsys_acquire(sme, true);
    543 	TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
    544 		if (strcmp(oedata->desc, edata->desc) == 0) {
    545 			sysmon_envsys_release(sme, true);
    546 			mutex_exit(&sme->sme_mtx);
    547 			return EEXIST;
    548 		}
    549 	}
    550 	/*
    551 	 * Ok, the sensor has been added into the device queue.
    552 	 */
    553 	TAILQ_INSERT_TAIL(&sme->sme_sensors_list, edata, sensors_head);
    554 
    555 	/*
    556 	 * Give the sensor a index position.
    557 	 */
    558 	edata->sensor = sme->sme_nsensors;
    559 	sme->sme_nsensors++;
    560 	sysmon_envsys_release(sme, true);
    561 	mutex_exit(&sme->sme_mtx);
    562 
    563 	DPRINTF(("%s: (%s) attached #%d (%s), units=%d (%s)\n",
    564 	    __func__, sme->sme_name, edata->sensor, edata->desc,
    565 	    sdt_units[i].type, sdt_units[i].desc));
    566 
    567 	return 0;
    568 }
    569 
    570 /*
    571  * sysmon_envsys_sensor_detach:
    572  *
    573  * 	+ Detachs a sensor from a sysmon_envsys device and decrements the
    574  * 	  sensors count on success.
    575  */
    576 int
    577 sysmon_envsys_sensor_detach(struct sysmon_envsys *sme, envsys_data_t *edata)
    578 {
    579 	envsys_data_t *oedata;
    580 	bool found = false;
    581 
    582 	KASSERT(sme != NULL || edata != NULL);
    583 
    584 	/*
    585 	 * Check the sensor is already on the list.
    586 	 */
    587 	mutex_enter(&sme->sme_mtx);
    588 	sysmon_envsys_acquire(sme, true);
    589 	TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
    590 		if (oedata->sensor == edata->sensor) {
    591 			found = true;
    592 			break;
    593 		}
    594 	}
    595 
    596 	if (!found) {
    597 		sysmon_envsys_release(sme, true);
    598 		mutex_exit(&sme->sme_mtx);
    599 		return EINVAL;
    600 	}
    601 
    602 	/*
    603 	 * remove it and decrement the sensors count.
    604 	 */
    605 	TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
    606 	sme->sme_nsensors--;
    607 	sysmon_envsys_release(sme, true);
    608 	mutex_exit(&sme->sme_mtx);
    609 
    610 	return 0;
    611 }
    612 
    613 
    614 /*
    615  * sysmon_envsys_register:
    616  *
    617  *	+ Register a sysmon envsys device.
    618  *	+ Create array of dictionaries for a device.
    619  */
    620 int
    621 sysmon_envsys_register(struct sysmon_envsys *sme)
    622 {
    623 	struct sme_evdrv {
    624 		SLIST_ENTRY(sme_evdrv) evdrv_head;
    625 		sme_event_drv_t *evdrv;
    626 	};
    627 	SLIST_HEAD(, sme_evdrv) sme_evdrv_list;
    628 	struct sme_evdrv *evdv = NULL;
    629 	struct sysmon_envsys *lsme;
    630 	prop_array_t array = NULL;
    631 	prop_dictionary_t dict, dict2;
    632 	envsys_data_t *edata = NULL;
    633 	sme_event_drv_t *this_evdrv;
    634 	int error = 0;
    635 
    636 	KASSERT(sme != NULL);
    637 	KASSERT(sme->sme_name != NULL);
    638 
    639 	/*
    640 	 * Check if requested sysmon_envsys device is valid
    641 	 * and does not exist already in the list.
    642 	 */
    643 	mutex_enter(&sme_global_mtx);
    644 	LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
    645 	       if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
    646 		       mutex_exit(&sme_global_mtx);
    647 		       return EEXIST;
    648 	       }
    649 	}
    650 	mutex_exit(&sme_global_mtx);
    651 
    652 	/*
    653 	 * sanity check: if SME_DISABLE_REFRESH is not set,
    654 	 * the sme_refresh function callback must be non NULL.
    655 	 */
    656 	if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0)
    657 		if (!sme->sme_refresh)
    658 			return EINVAL;
    659 
    660 	/*
    661 	 * If the list of sensors is empty, there's no point to continue...
    662 	 */
    663 	if (TAILQ_EMPTY(&sme->sme_sensors_list)) {
    664 		DPRINTF(("%s: sensors list empty for %s\n", __func__,
    665 		    sme->sme_name));
    666 		return ENOTSUP;
    667 	}
    668 
    669 	/*
    670 	 * Initialize the singly linked list for driver events.
    671 	 */
    672 	SLIST_INIT(&sme_evdrv_list);
    673 
    674 	array = prop_array_create();
    675 	if (!array)
    676 		return ENOMEM;
    677 
    678 	/*
    679 	 * Iterate over all sensors and create a dictionary per sensor.
    680 	 * We must respect the order in which the sensors were added.
    681 	 */
    682 	TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
    683 		dict = prop_dictionary_create();
    684 		if (!dict) {
    685 			error = ENOMEM;
    686 			goto out2;
    687 		}
    688 
    689 		/*
    690 		 * Create all objects in sensor's dictionary.
    691 		 */
    692 		this_evdrv = sme_add_sensor_dictionary(sme, array,
    693 						       dict, edata);
    694 		if (this_evdrv) {
    695 			evdv = kmem_zalloc(sizeof(*evdv), KM_SLEEP);
    696 			evdv->evdrv = this_evdrv;
    697 			SLIST_INSERT_HEAD(&sme_evdrv_list, evdv, evdrv_head);
    698 		}
    699 	}
    700 
    701 	/*
    702 	 * If the array does not contain any object (sensor), there's
    703 	 * no need to attach the driver.
    704 	 */
    705 	if (prop_array_count(array) == 0) {
    706 		error = EINVAL;
    707 		DPRINTF(("%s: empty array for '%s'\n", __func__,
    708 		    sme->sme_name));
    709 		goto out;
    710 	}
    711 
    712 	/*
    713 	 * Add the dictionary for the global properties of this device.
    714 	 */
    715 	dict2 = prop_dictionary_create();
    716 	if (!dict2) {
    717 		error = ENOMEM;
    718 		goto out;
    719 	}
    720 
    721 	error = sme_add_property_dictionary(sme, array, dict2);
    722 	if (error) {
    723 		prop_object_release(dict2);
    724 		goto out;
    725 	}
    726 
    727 	/*
    728 	 * Add the array into the global dictionary for the driver.
    729 	 *
    730 	 * <dict>
    731 	 * 	<key>foo0</key>
    732 	 * 	<array>
    733 	 * 		...
    734 	 */
    735 	mutex_enter(&sme_global_mtx);
    736 	if (!prop_dictionary_set(sme_propd, sme->sme_name, array)) {
    737 		error = EINVAL;
    738 		DPRINTF(("%s: prop_dictionary_set for '%s'\n", __func__,
    739 		    sme->sme_name));
    740 		goto out;
    741 	}
    742 
    743 	/*
    744 	 * Add the device into the list.
    745 	 */
    746 	LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list);
    747 	sme->sme_fsensor = sysmon_envsys_next_sensor_index;
    748 	sysmon_envsys_next_sensor_index += sme->sme_nsensors;
    749 	mutex_exit(&sme_global_mtx);
    750 
    751 out:
    752 	/*
    753 	 * No errors? register the events that were set in the driver
    754 	 * and make an initial data refresh if was requested.
    755 	 */
    756 	if (error == 0) {
    757 		sysmon_task_queue_init();
    758 		SLIST_FOREACH(evdv, &sme_evdrv_list, evdrv_head) {
    759 			sysmon_task_queue_sched(0,
    760 			    sme_event_drvadd, evdv->evdrv);
    761 		}
    762 		DPRINTF(("%s: driver '%s' registered (nsens=%d)\n",
    763 		    __func__, sme->sme_name, sme->sme_nsensors));
    764 
    765 		if (sme->sme_flags & SME_INIT_REFRESH)
    766 			sysmon_task_queue_sched(0, sme_initial_refresh, sme);
    767 	}
    768 
    769 out2:
    770 	while (!SLIST_EMPTY(&sme_evdrv_list)) {
    771 		evdv = SLIST_FIRST(&sme_evdrv_list);
    772 		SLIST_REMOVE_HEAD(&sme_evdrv_list, evdrv_head);
    773 		kmem_free(evdv, sizeof(*evdv));
    774 	}
    775 	if (!error)
    776 		return 0;
    777 
    778 	/*
    779 	 * Ugh... something wasn't right; unregister all events and sensors
    780 	 * previously assigned and destroy the array with all its objects.
    781 	 */
    782 	DPRINTF(("%s: failed to register '%s' (%d)\n", __func__,
    783 	    sme->sme_name, error));
    784 
    785 	sme_event_unregister_all(sme);
    786 	while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
    787 		edata = TAILQ_FIRST(&sme->sme_sensors_list);
    788 		TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
    789 	}
    790 	sysmon_envsys_destroy_plist(array);
    791 	return error;
    792 }
    793 
    794 /*
    795  * sysmon_envsys_destroy_plist:
    796  *
    797  * 	+ Remove all objects from the array of dictionaries that is
    798  * 	  created in a sysmon envsys device.
    799  */
    800 static void
    801 sysmon_envsys_destroy_plist(prop_array_t array)
    802 {
    803 	prop_object_iterator_t iter, iter2;
    804 	prop_dictionary_t dict;
    805 	prop_object_t obj;
    806 
    807 	KASSERT(array != NULL);
    808 	KASSERT(prop_object_type(array) == PROP_TYPE_ARRAY);
    809 
    810 	DPRINTFOBJ(("%s: objects in array=%d\n", __func__,
    811 	    prop_array_count(array)));
    812 
    813 	iter = prop_array_iterator(array);
    814 	if (!iter)
    815 		return;
    816 
    817 	while ((dict = prop_object_iterator_next(iter))) {
    818 		KASSERT(prop_object_type(dict) == PROP_TYPE_DICTIONARY);
    819 		iter2 = prop_dictionary_iterator(dict);
    820 		if (!iter2)
    821 			goto out;
    822 		DPRINTFOBJ(("%s: iterating over dictionary\n", __func__));
    823 		while ((obj = prop_object_iterator_next(iter2)) != NULL) {
    824 			DPRINTFOBJ(("%s: obj=%s\n", __func__,
    825 			    prop_dictionary_keysym_cstring_nocopy(obj)));
    826 			prop_dictionary_remove(dict,
    827 			    prop_dictionary_keysym_cstring_nocopy(obj));
    828 			prop_object_iterator_reset(iter2);
    829 		}
    830 		prop_object_iterator_release(iter2);
    831 		DPRINTFOBJ(("%s: objects in dictionary:%d\n",
    832 		    __func__, prop_dictionary_count(dict)));
    833 		prop_object_release(dict);
    834 	}
    835 
    836 out:
    837 	prop_object_iterator_release(iter);
    838 	prop_object_release(array);
    839 }
    840 
    841 /*
    842  * sysmon_envsys_unregister:
    843  *
    844  *	+ Unregister a sysmon envsys device.
    845  */
    846 void
    847 sysmon_envsys_unregister(struct sysmon_envsys *sme)
    848 {
    849 	prop_array_t array;
    850 
    851 	KASSERT(sme != NULL);
    852 
    853 	/*
    854 	 * Unregister all events associated with device.
    855 	 */
    856 	sme_event_unregister_all(sme);
    857 	/*
    858 	 * Decrement global sensors counter (only used for compatibility
    859 	 * with previous API) and remove the device from the list.
    860 	 */
    861 	mutex_enter(&sme_global_mtx);
    862 	sysmon_envsys_next_sensor_index -= sme->sme_nsensors;
    863 	LIST_REMOVE(sme, sme_list);
    864 	mutex_exit(&sme_global_mtx);
    865 
    866 	/*
    867 	 * Remove the device (and all its objects) from the global dictionary.
    868 	 */
    869 	array = prop_dictionary_get(sme_propd, sme->sme_name);
    870 	if (array && prop_object_type(array) == PROP_TYPE_ARRAY) {
    871 		mutex_enter(&sme_global_mtx);
    872 		prop_dictionary_remove(sme_propd, sme->sme_name);
    873 		mutex_exit(&sme_global_mtx);
    874 		sysmon_envsys_destroy_plist(array);
    875 	}
    876 	/*
    877 	 * And finally destroy the sysmon_envsys object.
    878 	 */
    879 	sysmon_envsys_destroy(sme);
    880 }
    881 
    882 /*
    883  * sysmon_envsys_find:
    884  *
    885  *	+ Find a sysmon envsys device and mark it as busy
    886  *	  once it's available.
    887  */
    888 struct sysmon_envsys *
    889 sysmon_envsys_find(const char *name)
    890 {
    891 	struct sysmon_envsys *sme;
    892 
    893 	mutex_enter(&sme_global_mtx);
    894 	LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
    895 		if (strcmp(sme->sme_name, name) == 0) {
    896 			sysmon_envsys_acquire(sme, false);
    897 			break;
    898 		}
    899 	}
    900 	mutex_exit(&sme_global_mtx);
    901 
    902 	return sme;
    903 }
    904 
    905 /*
    906  * Compatibility function with the old API.
    907  */
    908 struct sysmon_envsys *
    909 sysmon_envsys_find_40(u_int idx)
    910 {
    911 	struct sysmon_envsys *sme;
    912 
    913 	mutex_enter(&sme_global_mtx);
    914 	LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
    915 		if (idx >= sme->sme_fsensor &&
    916 	    	    idx < (sme->sme_fsensor + sme->sme_nsensors)) {
    917 			sysmon_envsys_acquire(sme, false);
    918 			break;
    919 		}
    920 	}
    921 	mutex_exit(&sme_global_mtx);
    922 
    923 	return sme;
    924 }
    925 
    926 /*
    927  * sysmon_envsys_acquire:
    928  *
    929  * 	+ Wait until a sysmon envsys device is available and mark
    930  * 	  it as busy.
    931  */
    932 void
    933 sysmon_envsys_acquire(struct sysmon_envsys *sme, bool locked)
    934 {
    935 	KASSERT(sme != NULL);
    936 
    937 	if (locked) {
    938 		while (sme->sme_flags & SME_FLAG_BUSY)
    939 			cv_wait(&sme->sme_condvar, &sme->sme_mtx);
    940 		sme->sme_flags |= SME_FLAG_BUSY;
    941 	} else {
    942 		mutex_enter(&sme->sme_mtx);
    943 		while (sme->sme_flags & SME_FLAG_BUSY)
    944 			cv_wait(&sme->sme_condvar, &sme->sme_mtx);
    945 		sme->sme_flags |= SME_FLAG_BUSY;
    946 		mutex_exit(&sme->sme_mtx);
    947 	}
    948 }
    949 
    950 /*
    951  * sysmon_envsys_release:
    952  *
    953  * 	+ Unmark a sysmon envsys device as busy, and notify
    954  * 	  waiters.
    955  */
    956 void
    957 sysmon_envsys_release(struct sysmon_envsys *sme, bool locked)
    958 {
    959 	KASSERT(sme != NULL);
    960 
    961 	if (locked) {
    962 		sme->sme_flags &= ~SME_FLAG_BUSY;
    963 		cv_broadcast(&sme->sme_condvar);
    964 	} else {
    965 		mutex_enter(&sme->sme_mtx);
    966 		sme->sme_flags &= ~SME_FLAG_BUSY;
    967 		cv_broadcast(&sme->sme_condvar);
    968 		mutex_exit(&sme->sme_mtx);
    969 	}
    970 }
    971 
    972 /*
    973  * sme_initial_refresh:
    974  *
    975  * 	+ Do an initial refresh of the sensors in a device just after
    976  * 	  interrupts are enabled in the autoconf(9) process.
    977  *
    978  */
    979 static void
    980 sme_initial_refresh(void *arg)
    981 {
    982 	struct sysmon_envsys *sme = arg;
    983 	envsys_data_t *edata;
    984 
    985 	mutex_enter(&sme->sme_mtx);
    986 	sysmon_envsys_acquire(sme, true);
    987 	TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head)
    988 		(*sme->sme_refresh)(sme, edata);
    989 	sysmon_envsys_release(sme, true);
    990 	mutex_exit(&sme->sme_mtx);
    991 }
    992 
    993 /*
    994  * sme_sensor_dictionary_get:
    995  *
    996  * 	+ Returns a dictionary of a device specified by its index
    997  * 	  position.
    998  */
    999 prop_dictionary_t
   1000 sme_sensor_dictionary_get(prop_array_t array, const char *index)
   1001 {
   1002 	prop_object_iterator_t iter;
   1003 	prop_dictionary_t dict;
   1004 	prop_object_t obj;
   1005 
   1006 	KASSERT(array != NULL || index != NULL);
   1007 
   1008 	iter = prop_array_iterator(array);
   1009 	if (!iter)
   1010 		return NULL;
   1011 
   1012 	while ((dict = prop_object_iterator_next(iter))) {
   1013 		obj = prop_dictionary_get(dict, "index");
   1014 		if (prop_string_equals_cstring(obj, index))
   1015 			break;
   1016 	}
   1017 
   1018 	prop_object_iterator_release(iter);
   1019 	return dict;
   1020 }
   1021 
   1022 /*
   1023  * sme_remove_userprops:
   1024  *
   1025  * 	+ Remove all properties from all devices that were set by
   1026  * 	  the ENVSYS_SETDICTIONARY ioctl.
   1027  */
   1028 static void
   1029 sme_remove_userprops(void)
   1030 {
   1031 	struct sysmon_envsys *sme;
   1032 	prop_array_t array;
   1033 	prop_dictionary_t sdict;
   1034 	envsys_data_t *edata = NULL;
   1035 	char tmp[ENVSYS_DESCLEN];
   1036 	int ptype;
   1037 
   1038 	mutex_enter(&sme_global_mtx);
   1039 	LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
   1040 		sysmon_envsys_acquire(sme, false);
   1041 		array = prop_dictionary_get(sme_propd, sme->sme_name);
   1042 
   1043 		TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1044 			(void)snprintf(tmp, sizeof(tmp), "sensor%d",
   1045 				       edata->sensor);
   1046 			sdict = sme_sensor_dictionary_get(array, tmp);
   1047 			KASSERT(sdict != NULL);
   1048 
   1049 			ptype = 0;
   1050 			if (edata->upropset & PROP_BATTCAP) {
   1051 				prop_dictionary_remove(sdict,
   1052 				    "critical-capacity");
   1053 				ptype = PENVSYS_EVENT_CAPACITY;
   1054 			}
   1055 
   1056 			if (edata->upropset & PROP_BATTWARN) {
   1057 				prop_dictionary_remove(sdict,
   1058 				    "warning-capacity");
   1059 				ptype = PENVSYS_EVENT_CAPACITY;
   1060 			}
   1061 			if (ptype != 0)
   1062 				sme_event_unregister(sme, edata->desc, ptype);
   1063 
   1064 			ptype = 0;
   1065 			if (edata->upropset & PROP_WARNMAX) {
   1066 				prop_dictionary_remove(sdict, "warning-max");
   1067 				ptype = PENVSYS_EVENT_LIMITS;
   1068 			}
   1069 
   1070 			if (edata->upropset & PROP_WARNMIN) {
   1071 				prop_dictionary_remove(sdict, "warning-min");
   1072 				ptype = PENVSYS_EVENT_LIMITS;
   1073 			}
   1074 
   1075 			if (edata->upropset & PROP_CRITMAX) {
   1076 				prop_dictionary_remove(sdict, "critical-max");
   1077 				ptype = PENVSYS_EVENT_LIMITS;
   1078 			}
   1079 
   1080 			if (edata->upropset & PROP_CRITMIN) {
   1081 				prop_dictionary_remove(sdict, "critical-min");
   1082 				ptype = PENVSYS_EVENT_LIMITS;
   1083 			}
   1084 			if (ptype != 0)
   1085 				sme_event_unregister(sme, edata->desc, ptype);
   1086 
   1087 			if (edata->upropset & PROP_RFACT) {
   1088 				(void)sme_sensor_upint32(sdict, "rfact", 0);
   1089 				edata->rfact = 0;
   1090 			}
   1091 
   1092 			if (edata->upropset & PROP_DESC)
   1093 				(void)sme_sensor_upstring(sdict,
   1094 			  	    "description", edata->desc);
   1095 
   1096 			if (edata->upropset)
   1097 				edata->upropset = 0;
   1098 		}
   1099 
   1100 		/*
   1101 		 * Restore default timeout value.
   1102 		 */
   1103 		sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
   1104 		sysmon_envsys_release(sme, false);
   1105 	}
   1106 	mutex_exit(&sme_global_mtx);
   1107 }
   1108 
   1109 /*
   1110  * sme_add_property_dictionary:
   1111  *
   1112  * 	+ Add global properties into a device.
   1113  */
   1114 static int
   1115 sme_add_property_dictionary(struct sysmon_envsys *sme, prop_array_t array,
   1116 			    prop_dictionary_t dict)
   1117 {
   1118 	prop_dictionary_t pdict;
   1119 	int error = 0;
   1120 
   1121 	pdict = prop_dictionary_create();
   1122 	if (!pdict)
   1123 		return EINVAL;
   1124 
   1125 	/*
   1126 	 * Add the 'refresh-timeout' object into the 'device-properties'
   1127 	 * dictionary. We use by default 30 seconds.
   1128 	 *
   1129 	 * 	...
   1130 	 * 	<dict>
   1131 	 * 		<key>device-properties</key>
   1132 	 * 		<dict>
   1133 	 * 			<key>refresh-timeout</key>
   1134 	 * 			<integer>120</integer<
   1135 	 * 		</dict<
   1136 	 * 	</dict>
   1137 	 * 	...
   1138 	 *
   1139 	 */
   1140 	if (!sme->sme_events_timeout)
   1141 		sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
   1142 
   1143 	if (!prop_dictionary_set_uint64(pdict, "refresh-timeout",
   1144 					sme->sme_events_timeout)) {
   1145 		error = EINVAL;
   1146 		goto out;
   1147 	}
   1148 
   1149 	if (!prop_dictionary_set(dict, "device-properties", pdict)) {
   1150 		error = EINVAL;
   1151 		goto out;
   1152 	}
   1153 
   1154 	/*
   1155 	 * Add the device dictionary into the sysmon envsys array.
   1156 	 */
   1157 	if (!prop_array_add(array, dict))
   1158 		error = EINVAL;
   1159 
   1160 out:
   1161 	prop_object_release(pdict);
   1162 	return error;
   1163 }
   1164 
   1165 /*
   1166  * sme_add_sensor_dictionary:
   1167  *
   1168  * 	+ Adds the sensor objects into the dictionary and returns a pointer
   1169  * 	  to a sme_event_drv_t object if a monitoring flag was set
   1170  * 	  (or NULL otherwise).
   1171  */
   1172 sme_event_drv_t *
   1173 sme_add_sensor_dictionary(struct sysmon_envsys *sme, prop_array_t array,
   1174 		    	  prop_dictionary_t dict, envsys_data_t *edata)
   1175 {
   1176 	const struct sme_description_table *sdt, *sdt_units;
   1177 	sme_event_drv_t *sme_evdrv_t = NULL;
   1178 	int i, j;
   1179 	char indexstr[ENVSYS_DESCLEN];
   1180 
   1181 	/*
   1182 	 * Find the correct units for this sensor.
   1183 	 */
   1184 	sdt_units = sme_get_description_table(SME_DESC_UNITS);
   1185 	for (i = 0; sdt_units[i].type != -1; i++)
   1186 		if (sdt_units[i].type == edata->units)
   1187 			break;
   1188 
   1189 	/*
   1190 	 * Add the index sensor string.
   1191 	 *
   1192 	 * 		...
   1193 	 * 		<key>index</eyr
   1194 	 * 		<string>sensor0</string>
   1195 	 * 		...
   1196 	 */
   1197 	(void)snprintf(indexstr, sizeof(indexstr), "sensor%d", edata->sensor);
   1198 	if (sme_sensor_upstring(dict, "index", indexstr))
   1199 		goto bad;
   1200 
   1201 	/*
   1202 	 * 		...
   1203 	 * 		<key>type</key>
   1204 	 * 		<string>foo</string>
   1205 	 * 		<key>description</key>
   1206 	 * 		<string>blah blah</string>
   1207 	 * 		...
   1208 	 */
   1209 	if (sme_sensor_upstring(dict, "type", sdt_units[i].desc))
   1210 		goto bad;
   1211 
   1212 	if (sme_sensor_upstring(dict, "description", edata->desc))
   1213 		goto bad;
   1214 
   1215 	/*
   1216 	 * Add sensor's state description.
   1217 	 *
   1218 	 * 		...
   1219 	 * 		<key>state</key>
   1220 	 * 		<string>valid</string>
   1221 	 * 		...
   1222 	 */
   1223 	sdt = sme_get_description_table(SME_DESC_STATES);
   1224 	for (j = 0; sdt[j].type != -1; j++)
   1225 		if (sdt[j].type == edata->state)
   1226 			break;
   1227 
   1228 	DPRINTF(("%s: sensor desc=%s type=%d state=%d\n",
   1229 	    __func__, edata->desc, edata->units, edata->state));
   1230 
   1231 	if (sme_sensor_upstring(dict, "state", sdt[j].desc))
   1232 		goto bad;
   1233 
   1234 	/*
   1235 	 * Add the monitoring boolean object:
   1236 	 *
   1237 	 * 		...
   1238 	 * 		<key>monitoring-supported</key>
   1239 	 * 		<true/>
   1240 	 *		...
   1241 	 *
   1242 	 * always false on Battery {capacity,charge}, Drive and Indicator types.
   1243 	 * They cannot be monitored.
   1244 	 *
   1245 	 */
   1246 	if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
   1247 	    (edata->units == ENVSYS_INDICATOR) ||
   1248 	    (edata->units == ENVSYS_DRIVE) ||
   1249 	    (edata->units == ENVSYS_BATTERY_CAPACITY) ||
   1250 	    (edata->units == ENVSYS_BATTERY_CHARGE)) {
   1251 		if (sme_sensor_upbool(dict, "monitoring-supported", false))
   1252 			goto out;
   1253 	} else {
   1254 		if (sme_sensor_upbool(dict, "monitoring-supported", true))
   1255 			goto out;
   1256 	}
   1257 
   1258 	/*
   1259 	 * Add the percentage boolean object, true if ENVSYS_FPERCENT
   1260 	 * is set or false otherwise.
   1261 	 *
   1262 	 * 		...
   1263 	 * 		<key>want-percentage</key>
   1264 	 * 		<true/>
   1265 	 * 		...
   1266 	 */
   1267 	if (edata->flags & ENVSYS_FPERCENT)
   1268 		if (sme_sensor_upbool(dict, "want-percentage", true))
   1269 			goto out;
   1270 
   1271 	/*
   1272 	 * Add the allow-rfact boolean object, true if
   1273 	 * ENVSYS_FCHANGERFACT if set or false otherwise.
   1274 	 *
   1275 	 * 		...
   1276 	 * 		<key>allow-rfact</key>
   1277 	 * 		<true/>
   1278 	 * 		...
   1279 	 */
   1280 	if (edata->units == ENVSYS_SVOLTS_DC ||
   1281 	    edata->units == ENVSYS_SVOLTS_AC) {
   1282 		if (edata->flags & ENVSYS_FCHANGERFACT) {
   1283 			if (sme_sensor_upbool(dict, "allow-rfact", true))
   1284 				goto out;
   1285 		} else {
   1286 			if (sme_sensor_upbool(dict, "allow-rfact", false))
   1287 				goto out;
   1288 		}
   1289 	}
   1290 
   1291 	/*
   1292 	 * Add the object for battery capacity sensors:
   1293 	 *
   1294 	 * 		...
   1295 	 * 		<key>battery-capacity</key>
   1296 	 * 		<string>NORMAL</string>
   1297 	 * 		...
   1298 	 */
   1299 	if (edata->units == ENVSYS_BATTERY_CAPACITY) {
   1300 		sdt = sme_get_description_table(SME_DESC_BATTERY_CAPACITY);
   1301 		for (j = 0; sdt[j].type != -1; j++)
   1302 			if (sdt[j].type == edata->value_cur)
   1303 				break;
   1304 
   1305 		if (sme_sensor_upstring(dict, "battery-capacity", sdt[j].desc))
   1306 			goto out;
   1307 	}
   1308 
   1309 	/*
   1310 	 * Add the drive-state object for drive sensors:
   1311 	 *
   1312 	 * 		...
   1313 	 * 		<key>drive-state</key>
   1314 	 * 		<string>drive is online</string>
   1315 	 * 		...
   1316 	 */
   1317 	if (edata->units == ENVSYS_DRIVE) {
   1318 		sdt = sme_get_description_table(SME_DESC_DRIVE_STATES);
   1319 		for (j = 0; sdt[j].type != -1; j++)
   1320 			if (sdt[j].type == edata->value_cur)
   1321 				break;
   1322 
   1323 		if (sme_sensor_upstring(dict, "drive-state", sdt[j].desc))
   1324 			goto out;
   1325 	}
   1326 
   1327 	/*
   1328 	 * Add the following objects if sensor is enabled...
   1329 	 */
   1330 	if (edata->state == ENVSYS_SVALID) {
   1331 		/*
   1332 		 * Add the following objects:
   1333 		 *
   1334 		 * 	...
   1335 		 * 	<key>rpms</key>
   1336 		 * 	<integer>2500</integer>
   1337 		 * 	<key>rfact</key>
   1338 		 * 	<integer>10000</integer>
   1339 		 * 	<key>cur-value</key>
   1340 	 	 * 	<integer>1250</integer>
   1341 	 	 * 	<key>min-value</key>
   1342 	 	 * 	<integer>800</integer>
   1343 	 	 * 	<key>max-value</integer>
   1344 	 	 * 	<integer>3000</integer>
   1345 	 	 * 	<key>avg-value</integer>
   1346 	 	 * 	<integer>1400</integer>
   1347 	 	 * 	...
   1348 	 	 */
   1349 		if (edata->units == ENVSYS_SFANRPM)
   1350 			if (sme_sensor_upuint32(dict, "rpms", edata->rpms))
   1351 				goto out;
   1352 
   1353 		if (edata->units == ENVSYS_SVOLTS_AC ||
   1354 	    	    edata->units == ENVSYS_SVOLTS_DC)
   1355 			if (sme_sensor_upint32(dict, "rfact", edata->rfact))
   1356 				goto out;
   1357 
   1358 		if (sme_sensor_upint32(dict, "cur-value", edata->value_cur))
   1359 			goto out;
   1360 
   1361 		if (edata->flags & ENVSYS_FVALID_MIN) {
   1362 			if (sme_sensor_upint32(dict,
   1363 					       "min-value",
   1364 					       edata->value_min))
   1365 			goto out;
   1366 		}
   1367 
   1368 		if (edata->flags & ENVSYS_FVALID_MAX) {
   1369 			if (sme_sensor_upint32(dict,
   1370 					       "max-value",
   1371 					       edata->value_max))
   1372 			goto out;
   1373 		}
   1374 
   1375 		if (edata->flags & ENVSYS_FVALID_AVG) {
   1376 			if (sme_sensor_upint32(dict,
   1377 					       "avg-value",
   1378 					       edata->value_avg))
   1379 			goto out;
   1380 		}
   1381 	}
   1382 
   1383 	/*
   1384 	 * 	...
   1385 	 * </dict>
   1386 	 *
   1387 	 * Add the dictionary into the array.
   1388 	 *
   1389 	 */
   1390 	if (!prop_array_add(array, dict)) {
   1391 		DPRINTF(("%s: prop_array_add\n", __func__));
   1392 		goto bad;
   1393 	}
   1394 
   1395 	/*
   1396 	 * Register a new event if a monitoring flag was set.
   1397 	 */
   1398 	if (edata->monitor) {
   1399 		sme_evdrv_t = kmem_zalloc(sizeof(*sme_evdrv_t), KM_SLEEP);
   1400 		sme_evdrv_t->sed_sdict = dict;
   1401 		sme_evdrv_t->sed_edata = edata;
   1402 		sme_evdrv_t->sed_sme = sme;
   1403 		sme_evdrv_t->sed_powertype = sdt_units[i].crittype;
   1404 	}
   1405 
   1406 out:
   1407 	return sme_evdrv_t;
   1408 
   1409 bad:
   1410 	prop_object_release(dict);
   1411 	return NULL;
   1412 }
   1413 
   1414 /*
   1415  * sme_update_dictionary:
   1416  *
   1417  * 	+ Update per-sensor dictionaries with new values if there were
   1418  * 	  changes, otherwise the object in dictionary is untouched.
   1419  */
   1420 int
   1421 sme_update_dictionary(struct sysmon_envsys *sme)
   1422 {
   1423 	const struct sme_description_table *sdt;
   1424 	envsys_data_t *edata;
   1425 	prop_object_t array, dict, obj, obj2;
   1426 	int j, error = 0;
   1427 
   1428 	/*
   1429 	 * Retrieve the array of dictionaries in device.
   1430 	 */
   1431 	array = prop_dictionary_get(sme_propd, sme->sme_name);
   1432 	if (prop_object_type(array) != PROP_TYPE_ARRAY) {
   1433 		DPRINTF(("%s: not an array (%s)\n", __func__, sme->sme_name));
   1434 		return EINVAL;
   1435 	}
   1436 
   1437 	/*
   1438 	 * Get the last dictionary on the array, this contains the
   1439 	 * 'device-properties' sub-dictionary.
   1440 	 */
   1441 	obj = prop_array_get(array, prop_array_count(array) - 1);
   1442 	if (!obj || prop_object_type(obj) != PROP_TYPE_DICTIONARY) {
   1443 		DPRINTF(("%s: not a device-properties dictionary\n", __func__));
   1444 		return EINVAL;
   1445 	}
   1446 
   1447 	obj2 = prop_dictionary_get(obj, "device-properties");
   1448 	if (!obj2)
   1449 		return EINVAL;
   1450 
   1451 	/*
   1452 	 * Update the 'refresh-timeout' property.
   1453 	 */
   1454 	if (!prop_dictionary_set_uint64(obj2, "refresh-timeout",
   1455 					sme->sme_events_timeout))
   1456 		return EINVAL;
   1457 
   1458 	/*
   1459 	 * - iterate over all sensors.
   1460 	 * - fetch new data.
   1461 	 * - check if data in dictionary is different than new data.
   1462 	 * - update dictionary if there were changes.
   1463 	 */
   1464 	DPRINTF(("%s: updating '%s' with nsensors=%d\n", __func__,
   1465 	    sme->sme_name, sme->sme_nsensors));
   1466 
   1467 	/*
   1468 	 * Don't bother with locking when traversing the queue,
   1469 	 * the device is already marked as busy; if a sensor
   1470 	 * is going to be removed or added it will have to wait.
   1471 	 */
   1472 	TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1473 		/*
   1474 		 * refresh sensor data via sme_refresh only if the
   1475 		 * flag is not set.
   1476 		 */
   1477 		if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0) {
   1478 			mutex_enter(&sme->sme_mtx);
   1479 			(*sme->sme_refresh)(sme, edata);
   1480 			mutex_exit(&sme->sme_mtx);
   1481 		}
   1482 
   1483 		/*
   1484 		 * retrieve sensor's dictionary.
   1485 		 */
   1486 		dict = prop_array_get(array, edata->sensor);
   1487 		if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) {
   1488 			DPRINTF(("%s: not a dictionary (%d:%s)\n",
   1489 			    __func__, edata->sensor, sme->sme_name));
   1490 			return EINVAL;
   1491 		}
   1492 
   1493 		/*
   1494 		 * update sensor's state.
   1495 		 */
   1496 		sdt = sme_get_description_table(SME_DESC_STATES);
   1497 		for (j = 0; sdt[j].type != -1; j++)
   1498 			if (sdt[j].type == edata->state)
   1499 				break;
   1500 
   1501 		DPRINTFOBJ(("%s: sensor #%d type=%d (%s) flags=%d\n",
   1502 		    __func__, edata->sensor, sdt[j].type, sdt[j].desc,
   1503 		    edata->flags));
   1504 
   1505 		error = sme_sensor_upstring(dict, "state", sdt[j].desc);
   1506 		if (error)
   1507 			break;
   1508 
   1509 		/*
   1510 		 * update sensor's type.
   1511 		 */
   1512 		sdt = sme_get_description_table(SME_DESC_UNITS);
   1513 		for (j = 0; sdt[j].type != -1; j++)
   1514 			if (sdt[j].type == edata->units)
   1515 				break;
   1516 
   1517 		DPRINTFOBJ(("%s: sensor #%d units=%d (%s)\n",
   1518 		    __func__, edata->sensor, sdt[j].type, sdt[j].desc));
   1519 
   1520 		error = sme_sensor_upstring(dict, "type", sdt[j].desc);
   1521 		if (error)
   1522 			break;
   1523 
   1524 		/*
   1525 		 * update sensor's current value.
   1526 		 */
   1527 		error = sme_sensor_upint32(dict,
   1528 					   "cur-value",
   1529 					   edata->value_cur);
   1530 		if (error)
   1531 			break;
   1532 
   1533 		/*
   1534 		 * Battery charge, Integer and Indicator types do not
   1535 		 * need the following objects, so skip them.
   1536 		 */
   1537 		if (edata->units == ENVSYS_INTEGER ||
   1538 		    edata->units == ENVSYS_INDICATOR ||
   1539 		    edata->units == ENVSYS_BATTERY_CHARGE)
   1540 			continue;
   1541 
   1542 		/*
   1543 		 * update sensor flags.
   1544 		 */
   1545 		if (edata->flags & ENVSYS_FPERCENT) {
   1546 			error = sme_sensor_upbool(dict,
   1547 						  "want-percentage",
   1548 						  true);
   1549 			if (error)
   1550 				break;
   1551 		}
   1552 
   1553 		/*
   1554 		 * update sensor's {avg,max,min}-value.
   1555 		 */
   1556 		if (edata->flags & ENVSYS_FVALID_MAX) {
   1557 			error = sme_sensor_upint32(dict,
   1558 						   "max-value",
   1559 						   edata->value_max);
   1560 			if (error)
   1561 				break;
   1562 		}
   1563 
   1564 		if (edata->flags & ENVSYS_FVALID_MIN) {
   1565 			error = sme_sensor_upint32(dict,
   1566 						   "min-value",
   1567 						   edata->value_min);
   1568 			if (error)
   1569 				break;
   1570 		}
   1571 
   1572 		if (edata->flags & ENVSYS_FVALID_AVG) {
   1573 			error = sme_sensor_upint32(dict,
   1574 						   "avg-value",
   1575 						   edata->value_avg);
   1576 			if (error)
   1577 				break;
   1578 		}
   1579 
   1580 		/*
   1581 		 * update 'rpms' only for ENVSYS_SFANRPM sensors.
   1582 		 */
   1583 		if (edata->units == ENVSYS_SFANRPM) {
   1584 			error = sme_sensor_upuint32(dict,
   1585 						    "rpms",
   1586 						    edata->rpms);
   1587 			if (error)
   1588 				break;
   1589 		}
   1590 
   1591 		/*
   1592 		 * update 'rfact' only for ENVSYS_SVOLTS_[AD]C sensors.
   1593 		 */
   1594 		if (edata->units == ENVSYS_SVOLTS_AC ||
   1595 		    edata->units == ENVSYS_SVOLTS_DC) {
   1596 			error = sme_sensor_upint32(dict,
   1597 						   "rfact",
   1598 						   edata->rfact);
   1599 			if (error)
   1600 				break;
   1601 		}
   1602 
   1603 		/*
   1604 		 * update 'drive-state' only for ENVSYS_DRIVE sensors.
   1605 		 */
   1606 		if (edata->units == ENVSYS_DRIVE) {
   1607 			sdt = sme_get_description_table(SME_DESC_DRIVE_STATES);
   1608 			for (j = 0; sdt[j].type != -1; j++)
   1609 				if (sdt[j].type == edata->value_cur)
   1610 					break;
   1611 
   1612 			error = sme_sensor_upstring(dict,
   1613 						    "drive-state",
   1614 						    sdt[j].desc);
   1615 			if (error)
   1616 				break;
   1617 		}
   1618 
   1619 		/*
   1620 		 * update 'battery-capacity' only for ENVSYS_BATTERY_CAPACITY
   1621 		 * sensors.
   1622 		 */
   1623 		if (edata->units == ENVSYS_BATTERY_CAPACITY) {
   1624 			sdt =
   1625 			  sme_get_description_table(SME_DESC_BATTERY_CAPACITY);
   1626 			for (j = 0; sdt[j].type != -1; j++)
   1627 				if (sdt[j].type == edata->value_cur)
   1628 					break;
   1629 
   1630 			error = sme_sensor_upstring(dict,
   1631 						    "battery-capacity",
   1632 						    sdt[j].desc);
   1633 			if (error)
   1634 				break;
   1635 		}
   1636 	}
   1637 
   1638 	return error;
   1639 }
   1640 
   1641 /*
   1642  * sme_userset_dictionary:
   1643  *
   1644  * 	+ Parse the userland dictionary and run the appropiate tasks
   1645  * 	  that were specified.
   1646  */
   1647 int
   1648 sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
   1649 		       prop_array_t array)
   1650 {
   1651 	const struct sme_description_table *sdt;
   1652 	envsys_data_t *edata;
   1653 	prop_dictionary_t dict, tdict = NULL;
   1654 	prop_object_t obj, obj1, obj2, tobj = NULL;
   1655 	uint64_t refresh_timo = 0;
   1656 	int32_t critmax = 0, warnmax = 0, warnmin = 0, critmin = 0;
   1657 	int props = 0;
   1658 	int i, error = 0;
   1659 	const char *blah;
   1660 	bool targetfound = false;
   1661 
   1662 	/*
   1663 	 * The user wanted to change the refresh timeout value for this
   1664 	 * device.
   1665 	 *
   1666 	 * Get the 'device-properties' object from the userland dictionary.
   1667 	 */
   1668 	obj = prop_dictionary_get(udict, "device-properties");
   1669 	if (obj && prop_object_type(obj) == PROP_TYPE_DICTIONARY) {
   1670 		/*
   1671 		 * Get the 'refresh-timeout' property for this device.
   1672 		 */
   1673 		obj1 = prop_dictionary_get(obj, "refresh-timeout");
   1674 		if (obj1 && prop_object_type(obj1) == PROP_TYPE_NUMBER) {
   1675 			targetfound = true;
   1676 			refresh_timo =
   1677 			    prop_number_unsigned_integer_value(obj1);
   1678 			if (refresh_timo < 1)
   1679 				error = EINVAL;
   1680 			else {
   1681 				mutex_enter(&sme->sme_mtx);
   1682 				sme->sme_events_timeout = refresh_timo;
   1683 				mutex_exit(&sme->sme_mtx);
   1684 		}
   1685 		}
   1686 		return error;
   1687 
   1688 	} else if (!obj) {
   1689 		/*
   1690 		 * Get sensor's index from userland dictionary.
   1691 		 */
   1692 		obj = prop_dictionary_get(udict, "index");
   1693 		if (!obj)
   1694 			return EINVAL;
   1695 		if (prop_object_type(obj) != PROP_TYPE_STRING) {
   1696 			DPRINTF(("%s: 'index' not a string\n", __func__));
   1697 			return EINVAL;
   1698 		}
   1699 	} else
   1700 		return EINVAL;
   1701 
   1702 	/*
   1703 	 * Don't bother with locking when traversing the queue,
   1704 	 * the device is already marked as busy; if a sensor
   1705 	 * is going to be removed or added it will have to wait.
   1706 	 */
   1707 	TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
   1708 		/*
   1709 		 * Get a dictionary and check if it's our sensor by checking
   1710 		 * at its index position.
   1711 		 */
   1712 		dict = prop_array_get(array, edata->sensor);
   1713 		obj1 = prop_dictionary_get(dict, "index");
   1714 
   1715 		/*
   1716 		 * is it our sensor?
   1717 		 */
   1718 		if (!prop_string_equals(obj1, obj))
   1719 			continue;
   1720 
   1721 		/*
   1722 		 * Check if a new description operation was
   1723 		 * requested by the user and set new description.
   1724 		 */
   1725 		obj2 = prop_dictionary_get(udict, "description");
   1726 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_STRING) {
   1727 			targetfound = true;
   1728 			blah = prop_string_cstring_nocopy(obj2);
   1729 
   1730 			/*
   1731 			 * Check for duplicate description.
   1732 			 */
   1733 			for (i = 0; i < sme->sme_nsensors; i++) {
   1734 				if (i == edata->sensor)
   1735 					continue;
   1736 				tdict = prop_array_get(array, i);
   1737 				tobj =
   1738 				    prop_dictionary_get(tdict, "description");
   1739 				if (prop_string_equals(obj2, tobj)) {
   1740 					error = EEXIST;
   1741 					goto out;
   1742 				}
   1743 			}
   1744 
   1745 			/*
   1746 			 * Update the object in dictionary.
   1747 			 */
   1748 			mutex_enter(&sme->sme_mtx);
   1749 			error = sme_sensor_upstring(dict,
   1750 						    "description",
   1751 						    blah);
   1752 			if (error) {
   1753 				mutex_exit(&sme->sme_mtx);
   1754 				goto out;
   1755 			}
   1756 
   1757 			DPRINTF(("%s: sensor%d changed desc to: %s\n",
   1758 			    __func__, edata->sensor, blah));
   1759 			edata->upropset |= PROP_DESC;
   1760 			mutex_exit(&sme->sme_mtx);
   1761 		}
   1762 
   1763 		/*
   1764 		 * did the user want to change the rfact?
   1765 		 */
   1766 		obj2 = prop_dictionary_get(udict, "rfact");
   1767 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1768 			targetfound = true;
   1769 			if (edata->flags & ENVSYS_FCHANGERFACT) {
   1770 				mutex_enter(&sme->sme_mtx);
   1771 				edata->rfact = prop_number_integer_value(obj2);
   1772 				edata->upropset |= PROP_RFACT;
   1773 				mutex_exit(&sme->sme_mtx);
   1774 				DPRINTF(("%s: sensor%d changed rfact to %d\n",
   1775 				    __func__, edata->sensor, edata->rfact));
   1776 			} else {
   1777 				error = ENOTSUP;
   1778 				goto out;
   1779 			}
   1780 		}
   1781 
   1782 		sdt = sme_get_description_table(SME_DESC_UNITS);
   1783 		for (i = 0; sdt[i].type != -1; i++)
   1784 			if (sdt[i].type == edata->units)
   1785 				break;
   1786 
   1787 		/*
   1788 		 * did the user want to set a critical capacity event?
   1789 		 */
   1790 		obj2 = prop_dictionary_get(udict, "critical-capacity");
   1791 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1792 			targetfound = true;
   1793 			if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
   1794 			    (edata->flags & ENVSYS_FPERCENT) == 0) {
   1795 				error = ENOTSUP;
   1796 				goto out;
   1797 			}
   1798 
   1799 			critmin = prop_number_integer_value(obj2);
   1800 			props |= PROP_BATTCAP;
   1801 		}
   1802 
   1803 		/*
   1804 		 * did the user want to set a warning capacity event?
   1805 		 */
   1806 		obj2 = prop_dictionary_get(udict, "warning-capacity");
   1807 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1808 			targetfound = true;
   1809 			if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
   1810 			    (edata->flags & ENVSYS_FPERCENT) == 0) {
   1811 				error = ENOTSUP;
   1812 				goto out;
   1813 			}
   1814 
   1815 			warnmin = prop_number_integer_value(obj2);
   1816 			props |= PROP_BATTWARN;
   1817 		}
   1818 
   1819 		/*
   1820 		 * did the user want to set a critical max event?
   1821 		 */
   1822 		obj2 = prop_dictionary_get(udict, "critical-max");
   1823 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1824 			targetfound = true;
   1825 			if (edata->units == ENVSYS_INDICATOR ||
   1826 			    edata->flags &
   1827 				    (ENVSYS_FPERCENT | ENVSYS_FMONNOTSUPP)) {
   1828 				error = ENOTSUP;
   1829 				goto out;
   1830 			}
   1831 
   1832 			critmax = prop_number_integer_value(obj2);
   1833 			props |= PROP_CRITMAX;
   1834 		}
   1835 
   1836 		/*
   1837 		 * did the user want to set a warning max event?
   1838 		 */
   1839 		obj2 = prop_dictionary_get(udict, "warning-max");
   1840 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1841 			targetfound = true;
   1842 			if (edata->units == ENVSYS_INDICATOR ||
   1843 			    edata->flags &
   1844 				    (ENVSYS_FPERCENT | ENVSYS_FMONNOTSUPP)) {
   1845 				error = ENOTSUP;
   1846 				goto out;
   1847 			}
   1848 
   1849 			warnmax = prop_number_integer_value(obj2);
   1850 			props |= PROP_WARNMAX;
   1851 		}
   1852 
   1853 		/*
   1854 		 * did the user want to set a critical min event?
   1855 		 */
   1856 		obj2 = prop_dictionary_get(udict, "critical-min");
   1857 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1858 			targetfound = true;
   1859 			if (edata->units == ENVSYS_INDICATOR ||
   1860 			    edata->flags &
   1861 				    (ENVSYS_FPERCENT | ENVSYS_FMONNOTSUPP)) {
   1862 				error = ENOTSUP;
   1863 				goto out;
   1864 			}
   1865 
   1866 			critmin = prop_number_integer_value(obj2);
   1867 			props |= PROP_CRITMIN;
   1868 		}
   1869 
   1870 		/*
   1871 		 * did the user want to set a warning min event?
   1872 		 */
   1873 		obj2 = prop_dictionary_get(udict, "warning-min");
   1874 		if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
   1875 			targetfound = true;
   1876 			if (edata->units == ENVSYS_INDICATOR ||
   1877 			    edata->flags &
   1878 				    (ENVSYS_FPERCENT | ENVSYS_FMONNOTSUPP)) {
   1879 				error = ENOTSUP;
   1880 				goto out;
   1881 			}
   1882 
   1883 			warnmin = prop_number_integer_value(obj2);
   1884 			props |= PROP_WARNMIN;
   1885 		}
   1886 
   1887 		if (props) {
   1888 			error = sme_event_register(dict,
   1889 					      edata,
   1890 					      sme,
   1891 					      critmax, warnmax, warnmin,
   1892 					      critmin, props,
   1893 					      (edata->flags & ENVSYS_FPERCENT)?
   1894 						PENVSYS_EVENT_CAPACITY:
   1895 						PENVSYS_EVENT_LIMITS,
   1896 					      sdt[i].crittype);
   1897 			if (error == EEXIST)
   1898 				error = 0;
   1899 			if (error)
   1900 				goto out;
   1901 
   1902 			mutex_enter(&sme->sme_mtx);
   1903 			edata->upropset |= props;
   1904 			mutex_exit(&sme->sme_mtx);
   1905 		}
   1906 
   1907 		/*
   1908 		 * All objects in dictionary were processed.
   1909 		 */
   1910 		break;
   1911 	}
   1912 
   1913 out:
   1914 	/*
   1915 	 * invalid target? return the error.
   1916 	 */
   1917 	if (!targetfound)
   1918 		error = EINVAL;
   1919 
   1920 	return error;
   1921 }
   1922