xref: /netbsd-src/sys/dev/sysmon/sysmon_envsys.c (revision bf4558f8cf493c3010a52da3d1cc8e8293620b51)
1*bf4558f8Sxtraeme /*	$NetBSD: sysmon_envsys.c,v 1.18 2007/07/01 07:36:45 xtraeme Exp $	*/
2*bf4558f8Sxtraeme 
3*bf4558f8Sxtraeme /*-
4*bf4558f8Sxtraeme  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5*bf4558f8Sxtraeme  * All rights reserved.
6*bf4558f8Sxtraeme  *
7*bf4558f8Sxtraeme  * This code is derived from software contributed to The NetBSD Foundation
8*bf4558f8Sxtraeme  * by Juan Romero Pardines.
9*bf4558f8Sxtraeme  *
10*bf4558f8Sxtraeme  * Redistribution and use in source and binary forms, with or without
11*bf4558f8Sxtraeme  * modification, are permitted provided that the following conditions
12*bf4558f8Sxtraeme  * are met:
13*bf4558f8Sxtraeme  * 1. Redistributions of source code must retain the above copyright
14*bf4558f8Sxtraeme  *    notice, this list of conditions and the following disclaimer.
15*bf4558f8Sxtraeme  * 2. Redistributions in binary form must reproduce the above copyright
16*bf4558f8Sxtraeme  *    notice, this list of conditions and the following disclaimer in the
17*bf4558f8Sxtraeme  *    documentation and/or other materials provided with the distribution.
18*bf4558f8Sxtraeme  * 3. All advertising materials mentioning features or use of this software
19*bf4558f8Sxtraeme  *    must display the following acknowledgement:
20*bf4558f8Sxtraeme  *      This product includes software developed by Juan Romero Pardines
21*bf4558f8Sxtraeme  *      for the NetBSD Foundation, Inc. and its contributors.
22*bf4558f8Sxtraeme  * 4. Neither the name of The NetBSD Foundation nor the names of its
23*bf4558f8Sxtraeme  *    contributors may be used to endorse or promote products derived
24*bf4558f8Sxtraeme  *    from this software without specific prior written permission.
25*bf4558f8Sxtraeme  *
26*bf4558f8Sxtraeme  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27*bf4558f8Sxtraeme  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28*bf4558f8Sxtraeme  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29*bf4558f8Sxtraeme  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30*bf4558f8Sxtraeme  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31*bf4558f8Sxtraeme  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32*bf4558f8Sxtraeme  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33*bf4558f8Sxtraeme  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34*bf4558f8Sxtraeme  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35*bf4558f8Sxtraeme  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36*bf4558f8Sxtraeme  * POSSIBILITY OF SUCH DAMAGE.
37*bf4558f8Sxtraeme  */
38e67f5e66Sthorpej 
39e67f5e66Sthorpej /*-
40e67f5e66Sthorpej  * Copyright (c) 2000 Zembu Labs, Inc.
41e67f5e66Sthorpej  * All rights reserved.
42e67f5e66Sthorpej  *
43e67f5e66Sthorpej  * Author: Jason R. Thorpe <thorpej@zembu.com>
44e67f5e66Sthorpej  *
45e67f5e66Sthorpej  * Redistribution and use in source and binary forms, with or without
46e67f5e66Sthorpej  * modification, are permitted provided that the following conditions
47e67f5e66Sthorpej  * are met:
48e67f5e66Sthorpej  * 1. Redistributions of source code must retain the above copyright
49e67f5e66Sthorpej  *    notice, this list of conditions and the following disclaimer.
50e67f5e66Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
51e67f5e66Sthorpej  *    notice, this list of conditions and the following disclaimer in the
52e67f5e66Sthorpej  *    documentation and/or other materials provided with the distribution.
53e67f5e66Sthorpej  * 3. All advertising materials mentioning features or use of this software
54e67f5e66Sthorpej  *    must display the following acknowledgement:
55e67f5e66Sthorpej  *	This product includes software developed by Zembu Labs, Inc.
56e67f5e66Sthorpej  * 4. Neither the name of Zembu Labs nor the names of its employees may
57e67f5e66Sthorpej  *    be used to endorse or promote products derived from this software
58e67f5e66Sthorpej  *    without specific prior written permission.
59e67f5e66Sthorpej  *
60e67f5e66Sthorpej  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
61e67f5e66Sthorpej  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
62e67f5e66Sthorpej  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
63e67f5e66Sthorpej  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
64e67f5e66Sthorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
65e67f5e66Sthorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66e67f5e66Sthorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67e67f5e66Sthorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68e67f5e66Sthorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69e67f5e66Sthorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70e67f5e66Sthorpej  */
71e67f5e66Sthorpej 
72e67f5e66Sthorpej /*
73*bf4558f8Sxtraeme  * Environmental sensor framework for sysmon, exported to userland
74*bf4558f8Sxtraeme  * with proplib(3).
75e67f5e66Sthorpej  */
76e67f5e66Sthorpej 
77640249d1Slukem #include <sys/cdefs.h>
78*bf4558f8Sxtraeme __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.18 2007/07/01 07:36:45 xtraeme Exp $");
79640249d1Slukem 
80e67f5e66Sthorpej #include <sys/param.h>
81*bf4558f8Sxtraeme #include <sys/types.h>
82e67f5e66Sthorpej #include <sys/conf.h>
83e67f5e66Sthorpej #include <sys/errno.h>
84e67f5e66Sthorpej #include <sys/kernel.h>
85e67f5e66Sthorpej #include <sys/systm.h>
86e67f5e66Sthorpej #include <sys/proc.h>
87*bf4558f8Sxtraeme #include <sys/mutex.h>
88*bf4558f8Sxtraeme #include <sys/kmem.h>
89e67f5e66Sthorpej 
90e67f5e66Sthorpej #include <dev/sysmon/sysmonvar.h>
91*bf4558f8Sxtraeme #include <dev/sysmon/sysmon_envsysvar.h>
92*bf4558f8Sxtraeme #include <dev/sysmon/sysmon_taskq.h>
93*bf4558f8Sxtraeme 
94*bf4558f8Sxtraeme #include "opt_compat_netbsd.h"
95*bf4558f8Sxtraeme 
96*bf4558f8Sxtraeme struct sme_sensor_type {
97*bf4558f8Sxtraeme 	int		type;
98*bf4558f8Sxtraeme 	int		crittype;
99*bf4558f8Sxtraeme 	const char	*desc;
100*bf4558f8Sxtraeme };
101*bf4558f8Sxtraeme 
102*bf4558f8Sxtraeme static const struct sme_sensor_type sme_sensor_type[] = {
103*bf4558f8Sxtraeme 	{ ENVSYS_STEMP,		PENVSYS_TYPE_TEMP,	"Temperature" },
104*bf4558f8Sxtraeme 	{ ENVSYS_SFANRPM,	PENVSYS_TYPE_FAN,	"Fan" },
105*bf4558f8Sxtraeme 	{ ENVSYS_SVOLTS_AC,	PENVSYS_TYPE_VOLTAGE,	"Voltage AC" },
106*bf4558f8Sxtraeme 	{ ENVSYS_SVOLTS_DC,	PENVSYS_TYPE_VOLTAGE,	"Voltage DC" },
107*bf4558f8Sxtraeme 	{ ENVSYS_SOHMS,		PENVSYS_TYPE_RESISTANCE,"Ohms" },
108*bf4558f8Sxtraeme 	{ ENVSYS_SWATTS,	PENVSYS_TYPE_POWER,	"Watts" },
109*bf4558f8Sxtraeme 	{ ENVSYS_SAMPS,		PENVSYS_TYPE_POWER,	"Ampere" },
110*bf4558f8Sxtraeme 	{ ENVSYS_SWATTHOUR,	PENVSYS_TYPE_BATTERY,	"Watt hour" },
111*bf4558f8Sxtraeme 	{ ENVSYS_SAMPHOUR,	PENVSYS_TYPE_BATTERY,	"Ampere hour" },
112*bf4558f8Sxtraeme 	{ ENVSYS_INDICATOR,	-1,			"Indicator" },
113*bf4558f8Sxtraeme 	{ ENVSYS_INTEGER,	-1,			"Integer" },
114*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE,		PENVSYS_TYPE_DRIVE,	"Drive" },
115*bf4558f8Sxtraeme 	{ -1,			-1,			NULL }
116*bf4558f8Sxtraeme };
117*bf4558f8Sxtraeme 
118*bf4558f8Sxtraeme struct sme_sensor_state {
119*bf4558f8Sxtraeme 	int		type;
120*bf4558f8Sxtraeme 	const char 	*desc;
121*bf4558f8Sxtraeme };
122*bf4558f8Sxtraeme 
123*bf4558f8Sxtraeme static const struct sme_sensor_state sme_sensor_state[] = {
124*bf4558f8Sxtraeme 	{ ENVSYS_SVALID,	"valid" },
125*bf4558f8Sxtraeme 	{ ENVSYS_SINVALID,	"invalid" },
126*bf4558f8Sxtraeme 	{ ENVSYS_SCRITICAL,	"critical" },
127*bf4558f8Sxtraeme 	{ ENVSYS_SCRITUNDER,	"critical-under" },
128*bf4558f8Sxtraeme 	{ ENVSYS_SCRITOVER,	"critical-over" },
129*bf4558f8Sxtraeme 	{ ENVSYS_SWARNUNDER,	"warning-under" },
130*bf4558f8Sxtraeme 	{ ENVSYS_SWARNOVER,	"warning-over" },
131*bf4558f8Sxtraeme 	{ -1,			"unknown" }
132*bf4558f8Sxtraeme };
133*bf4558f8Sxtraeme 
134*bf4558f8Sxtraeme static const struct sme_sensor_state sme_sensor_drive_state[] = {
135*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_EMPTY,		"drive state is unknown" },
136*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_READY,		"drive is ready" },
137*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_POWERUP,		"drive is powering up" },
138*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_ONLINE,		"drive is online" },
139*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_IDLE,		"drive is idle" },
140*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_ACTIVE,		"drive is active" },
141*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_REBUILD,		"drive is rebuilding" },
142*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_POWERDOWN,	"drive is powering down" },
143*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_FAIL,		"drive failed" },
144*bf4558f8Sxtraeme 	{ ENVSYS_DRIVE_PFAIL,		"drive degraded" },
145*bf4558f8Sxtraeme 	{ -1,				"unknown" }
146*bf4558f8Sxtraeme };
147*bf4558f8Sxtraeme 
148*bf4558f8Sxtraeme static prop_dictionary_t sme_propd;
149*bf4558f8Sxtraeme static kmutex_t sme_list_mtx;
150*bf4558f8Sxtraeme static kcondvar_t sme_list_cv;
151*bf4558f8Sxtraeme 
152*bf4558f8Sxtraeme #ifdef COMPAT_40
153*bf4558f8Sxtraeme static u_int sysmon_envsys_next_sensor_index = 0;
154*bf4558f8Sxtraeme static struct sysmon_envsys *sysmon_envsys_find_40(u_int);
155*bf4558f8Sxtraeme #endif
156*bf4558f8Sxtraeme 
157*bf4558f8Sxtraeme static void sysmon_envsys_release(struct sysmon_envsys *);
158*bf4558f8Sxtraeme 
159*bf4558f8Sxtraeme kmutex_t sme_mtx, sme_event_mtx;
160e67f5e66Sthorpej 
161e67f5e66Sthorpej /*
162*bf4558f8Sxtraeme  * sysmon_envsys_init:
163*bf4558f8Sxtraeme  *
164*bf4558f8Sxtraeme  * 	+ Initialize global mutexes, dictionary and the linked lists.
165e67f5e66Sthorpej  */
166*bf4558f8Sxtraeme void
167*bf4558f8Sxtraeme sysmon_envsys_init(void)
168*bf4558f8Sxtraeme {
169*bf4558f8Sxtraeme 	LIST_INIT(&sysmon_envsys_list);
170*bf4558f8Sxtraeme 	LIST_INIT(&sme_events_list);
171*bf4558f8Sxtraeme 	mutex_init(&sme_mtx, MUTEX_DRIVER, IPL_NONE);
172*bf4558f8Sxtraeme 	mutex_init(&sme_list_mtx, MUTEX_DRIVER, IPL_NONE);
173*bf4558f8Sxtraeme 	mutex_init(&sme_event_mtx, MUTEX_DRIVER, IPL_NONE);
174*bf4558f8Sxtraeme 	mutex_init(&sme_event_init_mtx, MUTEX_DRIVER, IPL_NONE);
175*bf4558f8Sxtraeme 	cv_init(&sme_list_cv, "smefind");
176*bf4558f8Sxtraeme 	sme_propd = prop_dictionary_create();
177*bf4558f8Sxtraeme }
178e67f5e66Sthorpej 
179e67f5e66Sthorpej /*
180e67f5e66Sthorpej  * sysmonopen_envsys:
181e67f5e66Sthorpej  *
182*bf4558f8Sxtraeme  *	+ Open the system monitor device.
183e67f5e66Sthorpej  */
184e67f5e66Sthorpej int
185*bf4558f8Sxtraeme sysmonopen_envsys(dev_t dev, int flag, int mode, struct lwp *l)
186e67f5e66Sthorpej {
187*bf4558f8Sxtraeme 	return 0;
188e67f5e66Sthorpej }
189e67f5e66Sthorpej 
190e67f5e66Sthorpej /*
191e67f5e66Sthorpej  * sysmonclose_envsys:
192e67f5e66Sthorpej  *
193*bf4558f8Sxtraeme  *	+ Close the system monitor device.
194e67f5e66Sthorpej  */
195e67f5e66Sthorpej int
196*bf4558f8Sxtraeme sysmonclose_envsys(dev_t dev, int flag, int mode, struct lwp *l)
197e67f5e66Sthorpej {
19857b53bc9Sjdolecek 	/* Nothing to do */
199*bf4558f8Sxtraeme 	return 0;
200e67f5e66Sthorpej }
201e67f5e66Sthorpej 
202e67f5e66Sthorpej /*
203e67f5e66Sthorpej  * sysmonioctl_envsys:
204e67f5e66Sthorpej  *
205*bf4558f8Sxtraeme  *	+ Perform an envsys control request.
206e67f5e66Sthorpej  */
207e67f5e66Sthorpej int
208*bf4558f8Sxtraeme sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
209e67f5e66Sthorpej {
210*bf4558f8Sxtraeme 	struct sysmon_envsys *sme = NULL;
211e67f5e66Sthorpej 	int error = 0;
212*bf4558f8Sxtraeme #ifdef COMPAT_40
213e67f5e66Sthorpej 	u_int oidx;
214*bf4558f8Sxtraeme #endif
215e67f5e66Sthorpej 
216e67f5e66Sthorpej 	switch (cmd) {
217*bf4558f8Sxtraeme 	case ENVSYS_GETDICTIONARY:
218e67f5e66Sthorpej 	    {
219*bf4558f8Sxtraeme 		struct plistref *plist = (struct plistref *)data;
22059e0238fSexplorer 
221*bf4558f8Sxtraeme 		/*
222*bf4558f8Sxtraeme 		 * Update all sysmon envsys devices dictionaries with
223*bf4558f8Sxtraeme 		 * new data if it's different than we have currently
224*bf4558f8Sxtraeme 		 * in the dictionary.
225*bf4558f8Sxtraeme 		 */
226*bf4558f8Sxtraeme 		mutex_enter(&sme_mtx);
227*bf4558f8Sxtraeme 		LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
228*bf4558f8Sxtraeme 			if (sme == NULL)
229*bf4558f8Sxtraeme 				continue;
23059e0238fSexplorer 
231*bf4558f8Sxtraeme 			error = sme_update_dictionary(sme);
232*bf4558f8Sxtraeme 			if (error) {
233*bf4558f8Sxtraeme 				DPRINTF(("%s: sme_update_dictionary, "
234*bf4558f8Sxtraeme 				    "error=%d\n", __func__, error));
235*bf4558f8Sxtraeme 				mutex_exit(&sme_mtx);
236*bf4558f8Sxtraeme 				return error;
237*bf4558f8Sxtraeme 			}
238*bf4558f8Sxtraeme 		}
239*bf4558f8Sxtraeme 		mutex_exit(&sme_mtx);
240*bf4558f8Sxtraeme 		/*
241*bf4558f8Sxtraeme 		 * Copy global dictionary to userland.
242*bf4558f8Sxtraeme 		 */
243*bf4558f8Sxtraeme 		error = prop_dictionary_copyout_ioctl(plist, cmd, sme_propd);
244*bf4558f8Sxtraeme 		break;
245*bf4558f8Sxtraeme 	    }
246*bf4558f8Sxtraeme 	case ENVSYS_SETDICTIONARY:
247*bf4558f8Sxtraeme 	    {
248*bf4558f8Sxtraeme 		const struct plistref *plist = (const struct plistref *)data;
249*bf4558f8Sxtraeme 		prop_dictionary_t udict;
250*bf4558f8Sxtraeme 		prop_object_t obj;
251*bf4558f8Sxtraeme 		const char *devname = NULL;
25259e0238fSexplorer 
253*bf4558f8Sxtraeme 		/*
254*bf4558f8Sxtraeme 		 * Get dictionary from userland.
255*bf4558f8Sxtraeme 		 */
256*bf4558f8Sxtraeme 		error = prop_dictionary_copyin_ioctl(plist, cmd, &udict);
257*bf4558f8Sxtraeme 		DPRINTF(("%s: copyin_ioctl error=%d\n", __func__, error));
258*bf4558f8Sxtraeme 		if (error)
259*bf4558f8Sxtraeme 			break;
260*bf4558f8Sxtraeme 
261*bf4558f8Sxtraeme 		/*
262*bf4558f8Sxtraeme 		 * Parse "driver-name" key to obtain the driver we
263*bf4558f8Sxtraeme 		 * are searching for.
264*bf4558f8Sxtraeme 		 */
265*bf4558f8Sxtraeme 		obj = prop_dictionary_get(udict, "driver-name");
266*bf4558f8Sxtraeme 		if (obj == NULL || prop_object_type(obj) != PROP_TYPE_STRING) {
267*bf4558f8Sxtraeme 			DPRINTF(("%s: driver-name failed\n", __func__));
268*bf4558f8Sxtraeme 			prop_object_release(udict);
269*bf4558f8Sxtraeme 			error = EINVAL;
27059e0238fSexplorer 			break;
27159e0238fSexplorer 		}
272e67f5e66Sthorpej 
273*bf4558f8Sxtraeme 		/* driver name */
274*bf4558f8Sxtraeme 		devname = prop_string_cstring_nocopy(obj);
275*bf4558f8Sxtraeme 
276*bf4558f8Sxtraeme 		/* find the correct sme device */
277*bf4558f8Sxtraeme 		sme = sysmon_envsys_find(devname);
278e67f5e66Sthorpej 		if (sme == NULL) {
279*bf4558f8Sxtraeme 			DPRINTF(("%s: NULL sme\n", __func__));
280*bf4558f8Sxtraeme 			prop_object_release(udict);
281*bf4558f8Sxtraeme 			error = EINVAL;
282e67f5e66Sthorpej 			break;
283e67f5e66Sthorpej 		}
284*bf4558f8Sxtraeme 
285*bf4558f8Sxtraeme 		/*
286*bf4558f8Sxtraeme 		 * Find the correct array object with the string supplied
287*bf4558f8Sxtraeme 		 * by the userland dictionary.
288*bf4558f8Sxtraeme 		 */
289*bf4558f8Sxtraeme 		obj = prop_dictionary_get(sme_propd, devname);
290*bf4558f8Sxtraeme 		if (prop_object_type(obj) != PROP_TYPE_ARRAY) {
291*bf4558f8Sxtraeme 			DPRINTF(("%s: array device failed\n", __func__));
292*bf4558f8Sxtraeme 			prop_object_release(udict);
293*bf4558f8Sxtraeme 			error = EINVAL;
29459e0238fSexplorer 			break;
29559e0238fSexplorer 		}
296*bf4558f8Sxtraeme 
297*bf4558f8Sxtraeme 		/* do the real work now */
298*bf4558f8Sxtraeme 		error = sme_userset_dictionary(sme, udict, obj);
299e67f5e66Sthorpej 		sysmon_envsys_release(sme);
300e67f5e66Sthorpej 		break;
301e67f5e66Sthorpej 	    }
302*bf4558f8Sxtraeme 	    /*
303*bf4558f8Sxtraeme 	     * Compatibility functions with the old interface, only
304*bf4558f8Sxtraeme 	     * implemented ENVSYS_GTREDATA and ENVSYS_GTREINFO; enough
305*bf4558f8Sxtraeme 	     * to make old applications work.
306*bf4558f8Sxtraeme 	     */
307*bf4558f8Sxtraeme #ifdef COMPAT_40
308e67f5e66Sthorpej 	case ENVSYS_GTREDATA:
309e67f5e66Sthorpej 	    {
310e67f5e66Sthorpej 		struct envsys_tre_data *tred = (void *)data;
311*bf4558f8Sxtraeme 		envsys_data_t *edata = NULL;
312e67f5e66Sthorpej 
313e67f5e66Sthorpej 		tred->validflags = 0;
314e67f5e66Sthorpej 
315*bf4558f8Sxtraeme 		sme = sysmon_envsys_find_40(tred->sensor);
316e67f5e66Sthorpej 		if (sme == NULL)
317e67f5e66Sthorpej 			break;
318*bf4558f8Sxtraeme 
319*bf4558f8Sxtraeme 		mutex_enter(&sme_mtx);
320e67f5e66Sthorpej 		oidx = tred->sensor;
321e67f5e66Sthorpej 		tred->sensor = SME_SENSOR_IDX(sme, tred->sensor);
322*bf4558f8Sxtraeme 
323*bf4558f8Sxtraeme 		DPRINTFOBJ(("%s: sensor=%d oidx=%d dev=%s nsensors=%d\n",
324*bf4558f8Sxtraeme 		    __func__, tred->sensor, oidx, sme->sme_name,
325*bf4558f8Sxtraeme 		    sme->sme_nsensors));
326*bf4558f8Sxtraeme 
327*bf4558f8Sxtraeme 		edata = &sme->sme_sensor_data[tred->sensor];
328*bf4558f8Sxtraeme 
329*bf4558f8Sxtraeme 		if (tred->sensor < sme->sme_nsensors) {
330*bf4558f8Sxtraeme 			if ((sme->sme_flags & SME_DISABLE_GTREDATA) == 0) {
331*bf4558f8Sxtraeme 				error = (*sme->sme_gtredata)(sme, edata);
332*bf4558f8Sxtraeme 				if (error) {
333*bf4558f8Sxtraeme 					DPRINTF(("%s: sme_gtredata failed\n",
334*bf4558f8Sxtraeme 				    	    __func__));
335*bf4558f8Sxtraeme 					mutex_exit(&sme_mtx);
336*bf4558f8Sxtraeme 					return error;
337*bf4558f8Sxtraeme 				}
338*bf4558f8Sxtraeme 			}
339*bf4558f8Sxtraeme 
340*bf4558f8Sxtraeme 			/* copy required values to the old interface */
341*bf4558f8Sxtraeme 			tred->sensor = edata->sensor;
342*bf4558f8Sxtraeme 			tred->cur.data_us = edata->value_cur;
343*bf4558f8Sxtraeme 			tred->cur.data_s = edata->value_cur;
344*bf4558f8Sxtraeme 			tred->max.data_us = edata->value_max;
345*bf4558f8Sxtraeme 			tred->max.data_s = edata->value_max;
346*bf4558f8Sxtraeme 			tred->min.data_us = edata->value_min;
347*bf4558f8Sxtraeme 			tred->min.data_s = edata->value_min;
348*bf4558f8Sxtraeme 			tred->avg.data_us = edata->value_avg;
349*bf4558f8Sxtraeme 			tred->avg.data_s = edata->value_avg;
350*bf4558f8Sxtraeme 			tred->units = edata->units;
351*bf4558f8Sxtraeme 
352*bf4558f8Sxtraeme 			/* mark invalid sensors */
353*bf4558f8Sxtraeme 			if (edata->state == ENVSYS_SINVALID) {
354*bf4558f8Sxtraeme 				tred->validflags &=
355*bf4558f8Sxtraeme 				    ~(ENVSYS_FVALID|ENVSYS_FCURVALID);
356*bf4558f8Sxtraeme 				tred->validflags &=
357*bf4558f8Sxtraeme 				    ~(ENVSYS_FMAXVALID|ENVSYS_FFRACVALID);
358*bf4558f8Sxtraeme 				tred->cur.data_us = tred->cur.data_s = 0;
359*bf4558f8Sxtraeme 			}
360*bf4558f8Sxtraeme 
361*bf4558f8Sxtraeme 			tred->validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
362*bf4558f8Sxtraeme 			if (edata->flags & ENVSYS_FPERCENT)
363*bf4558f8Sxtraeme 				tred->validflags |=
364*bf4558f8Sxtraeme 				    (ENVSYS_FMAXVALID|ENVSYS_FFRACVALID);
365*bf4558f8Sxtraeme 
366*bf4558f8Sxtraeme 			DPRINTFOBJ(("%s: sensor=%s tred->cur.data_s=%d\n",
367*bf4558f8Sxtraeme 			    __func__, edata->desc, tred->cur.data_s));
368*bf4558f8Sxtraeme 			DPRINTFOBJ(("%s: tred->validflags=%d tred->units=%d"
369*bf4558f8Sxtraeme 			    " tred->sensor=%d\n", __func__, tred->validflags,
370*bf4558f8Sxtraeme 			    tred->units, tred->sensor));
37157b53bc9Sjdolecek 		}
372e67f5e66Sthorpej 		tred->sensor = oidx;
373*bf4558f8Sxtraeme 		mutex_exit(&sme_mtx);
374*bf4558f8Sxtraeme 
375e67f5e66Sthorpej 		break;
376e67f5e66Sthorpej 	    }
377e67f5e66Sthorpej 	case ENVSYS_GTREINFO:
378e67f5e66Sthorpej 	    {
379e67f5e66Sthorpej 		struct envsys_basic_info *binfo = (void *)data;
380*bf4558f8Sxtraeme 		envsys_data_t *edata = NULL;
381e67f5e66Sthorpej 
382e67f5e66Sthorpej 		binfo->validflags = 0;
383e67f5e66Sthorpej 
384*bf4558f8Sxtraeme 		sme = sysmon_envsys_find_40(binfo->sensor);
385e67f5e66Sthorpej 		if (sme == NULL)
386e67f5e66Sthorpej 			break;
387*bf4558f8Sxtraeme 
388*bf4558f8Sxtraeme 		mutex_enter(&sme_mtx);
389e67f5e66Sthorpej 		oidx = binfo->sensor;
390e67f5e66Sthorpej 		binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
391*bf4558f8Sxtraeme 
392*bf4558f8Sxtraeme 		edata = &sme->sme_sensor_data[binfo->sensor];
393*bf4558f8Sxtraeme 
394*bf4558f8Sxtraeme 		/* skip invalid sensors */
395*bf4558f8Sxtraeme 		if (edata->state == ENVSYS_SINVALID) {
396*bf4558f8Sxtraeme 			binfo->validflags &= ~(ENVSYS_FVALID|ENVSYS_FCURVALID);
397*bf4558f8Sxtraeme 			binfo->validflags &=
398*bf4558f8Sxtraeme 			    ~(ENVSYS_FMAXVALID|ENVSYS_FFRACVALID);
399*bf4558f8Sxtraeme 		}
400*bf4558f8Sxtraeme 
401*bf4558f8Sxtraeme 		if (binfo->sensor < sme->sme_nsensors) {
402*bf4558f8Sxtraeme 			binfo->validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
403*bf4558f8Sxtraeme 			if (edata->flags & ENVSYS_FPERCENT)
404*bf4558f8Sxtraeme 				binfo->validflags |=
405*bf4558f8Sxtraeme 				    (ENVSYS_FMAXVALID|ENVSYS_FFRACVALID);
406*bf4558f8Sxtraeme 			binfo->units = edata->units;
407*bf4558f8Sxtraeme 			(void)strlcpy(binfo->desc, edata->desc,
408*bf4558f8Sxtraeme 			    sizeof(binfo->desc));
409*bf4558f8Sxtraeme 		}
410*bf4558f8Sxtraeme 
411*bf4558f8Sxtraeme 		DPRINTFOBJ(("%s: binfo->units=%d binfo->validflags=%d\n",
412*bf4558f8Sxtraeme 		    __func__, binfo->units, binfo->validflags));
413*bf4558f8Sxtraeme 		DPRINTFOBJ(("%s: binfo->desc=%s binfo->sensor=%d\n",
414*bf4558f8Sxtraeme 		    __func__, binfo->desc, binfo->sensor));
415*bf4558f8Sxtraeme 
416e67f5e66Sthorpej 		binfo->sensor = oidx;
417*bf4558f8Sxtraeme 		mutex_exit(&sme_mtx);
418*bf4558f8Sxtraeme 
419*bf4558f8Sxtraeme 		break;
420*bf4558f8Sxtraeme 	    }
421*bf4558f8Sxtraeme #endif /* COMPAT_40 */
422*bf4558f8Sxtraeme 	default:
423*bf4558f8Sxtraeme 		error = ENOTTY;
424e67f5e66Sthorpej 		break;
425e67f5e66Sthorpej 	}
426e67f5e66Sthorpej 
427*bf4558f8Sxtraeme 	return error;
428e67f5e66Sthorpej }
429e67f5e66Sthorpej 
430e67f5e66Sthorpej /*
431e67f5e66Sthorpej  * sysmon_envsys_register:
432e67f5e66Sthorpej  *
433*bf4558f8Sxtraeme  *	+ Register an envsys device.
434*bf4558f8Sxtraeme  *	+ Create device dictionary.
435e67f5e66Sthorpej  */
436e67f5e66Sthorpej int
437e67f5e66Sthorpej sysmon_envsys_register(struct sysmon_envsys *sme)
438e67f5e66Sthorpej {
439*bf4558f8Sxtraeme 	struct sysmon_envsys *lsme;
440e67f5e66Sthorpej 	int error = 0;
441e67f5e66Sthorpej 
442*bf4558f8Sxtraeme 	/*
443*bf4558f8Sxtraeme 	 * sanity check 1, make sure the driver has initialized
444*bf4558f8Sxtraeme 	 * the sensors count or the value is not too high.
445*bf4558f8Sxtraeme 	 */
446*bf4558f8Sxtraeme 	if (!sme->sme_nsensors || sme->sme_nsensors > ENVSYS_MAXSENSORS)
447*bf4558f8Sxtraeme 		return EINVAL;
448e67f5e66Sthorpej 
449*bf4558f8Sxtraeme 	/*
450*bf4558f8Sxtraeme 	 * sanity check 2, make sure that sme->sme_name and
451*bf4558f8Sxtraeme 	 * sme->sme_data are not NULL.
452*bf4558f8Sxtraeme 	 */
453*bf4558f8Sxtraeme 	if (sme->sme_name == NULL || sme->sme_sensor_data == NULL)
454*bf4558f8Sxtraeme 		return EINVAL;
455*bf4558f8Sxtraeme 
456*bf4558f8Sxtraeme 	/*
457*bf4558f8Sxtraeme 	 * sanity check 3, if SME_DISABLE_GTREDATA is not set
458*bf4558f8Sxtraeme 	 * the sme_gtredata function callback must be non NULL.
459*bf4558f8Sxtraeme 	 */
460*bf4558f8Sxtraeme 	if ((sme->sme_flags & SME_DISABLE_GTREDATA) == 0) {
461*bf4558f8Sxtraeme 		if (sme->sme_gtredata == NULL)
462*bf4558f8Sxtraeme 			return EINVAL;
463e67f5e66Sthorpej 	}
464e67f5e66Sthorpej 
465*bf4558f8Sxtraeme 	/*
466*bf4558f8Sxtraeme 	 * - check if requested sysmon_envsys device is valid
467*bf4558f8Sxtraeme 	 *   and does not exist already in the list.
468*bf4558f8Sxtraeme 	 * - add device into the list.
469*bf4558f8Sxtraeme 	 * - create the plist structure.
470*bf4558f8Sxtraeme 	 */
471*bf4558f8Sxtraeme 	mutex_enter(&sme_list_mtx);
472*bf4558f8Sxtraeme 	LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
473*bf4558f8Sxtraeme 	       if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
474*bf4558f8Sxtraeme 		       mutex_exit(&sme_list_mtx);
475*bf4558f8Sxtraeme 		       error = EEXIST;
476*bf4558f8Sxtraeme 		       goto out;
477*bf4558f8Sxtraeme 	       }
478*bf4558f8Sxtraeme 	}
479*bf4558f8Sxtraeme #ifdef COMPAT_40
480e67f5e66Sthorpej 	sme->sme_fsensor = sysmon_envsys_next_sensor_index;
481e67f5e66Sthorpej 	sysmon_envsys_next_sensor_index += sme->sme_nsensors;
482*bf4558f8Sxtraeme #endif
483*bf4558f8Sxtraeme 	mutex_exit(&sme_list_mtx);
484*bf4558f8Sxtraeme 	error = sysmon_envsys_createplist(sme);
485*bf4558f8Sxtraeme 	if (!error) {
486*bf4558f8Sxtraeme 		mutex_enter(&sme_list_mtx);
487e67f5e66Sthorpej 		LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list);
488*bf4558f8Sxtraeme 		mutex_exit(&sme_list_mtx);
489*bf4558f8Sxtraeme 	}
490e67f5e66Sthorpej 
491e67f5e66Sthorpej out:
492*bf4558f8Sxtraeme 	return error;
493e67f5e66Sthorpej }
494e67f5e66Sthorpej 
495e67f5e66Sthorpej /*
496e67f5e66Sthorpej  * sysmon_envsys_unregister:
497e67f5e66Sthorpej  *
498*bf4558f8Sxtraeme  *	+ Unregister an envsys device.
499*bf4558f8Sxtraeme  *	+ Unregister all events associated with this device.
500*bf4558f8Sxtraeme  *	+ Remove device dictionary.
501e67f5e66Sthorpej  */
502e67f5e66Sthorpej void
503e67f5e66Sthorpej sysmon_envsys_unregister(struct sysmon_envsys *sme)
504e67f5e66Sthorpej {
505*bf4558f8Sxtraeme 	sme_event_t *see;
506e67f5e66Sthorpej 
507*bf4558f8Sxtraeme 	mutex_enter(&sme_list_mtx);
508104f2a80Syamt 	while (sme->sme_flags & SME_FLAG_BUSY) {
50944d0d572Syamt 		sme->sme_flags |= SME_FLAG_WANTED;
510*bf4558f8Sxtraeme 		cv_wait(&sme_list_cv, &sme_list_mtx);
511*bf4558f8Sxtraeme 	}
512*bf4558f8Sxtraeme 	prop_dictionary_remove(sme_propd, sme->sme_name);
513*bf4558f8Sxtraeme 	LIST_FOREACH(see, &sme_events_list, see_list) {
514*bf4558f8Sxtraeme 		if (strcmp(see->pes.pes_dvname, sme->sme_name) == 0)
515*bf4558f8Sxtraeme 			sme_event_unregister(see->pes.pes_sensname,
516*bf4558f8Sxtraeme 			    see->type);
517104f2a80Syamt 	}
518e67f5e66Sthorpej 	LIST_REMOVE(sme, sme_list);
519*bf4558f8Sxtraeme 	mutex_exit(&sme_list_mtx);
520e67f5e66Sthorpej }
521e67f5e66Sthorpej 
522e67f5e66Sthorpej /*
523e67f5e66Sthorpej  * sysmon_envsys_find:
524e67f5e66Sthorpej  *
525*bf4558f8Sxtraeme  *	+ Find an envsys device.
526e67f5e66Sthorpej  */
527e67f5e66Sthorpej struct sysmon_envsys *
528*bf4558f8Sxtraeme sysmon_envsys_find(const char *name)
529e67f5e66Sthorpej {
530e67f5e66Sthorpej 	struct sysmon_envsys *sme;
531e67f5e66Sthorpej 
532*bf4558f8Sxtraeme 	mutex_enter(&sme_list_mtx);
533104f2a80Syamt again:
534e67f5e66Sthorpej 	for (sme = LIST_FIRST(&sysmon_envsys_list); sme != NULL;
535e67f5e66Sthorpej 	     sme = LIST_NEXT(sme, sme_list)) {
536*bf4558f8Sxtraeme 			if (strcmp(sme->sme_name, name) == 0) {
537104f2a80Syamt 				if (sme->sme_flags & SME_FLAG_BUSY) {
53844d0d572Syamt 					sme->sme_flags |= SME_FLAG_WANTED;
539*bf4558f8Sxtraeme 					cv_wait(&sme_list_cv, &sme_list_mtx);
540104f2a80Syamt 					goto again;
541104f2a80Syamt 				}
542104f2a80Syamt 				sme->sme_flags |= SME_FLAG_BUSY;
543104f2a80Syamt 				break;
544104f2a80Syamt 			}
545e67f5e66Sthorpej 	}
546*bf4558f8Sxtraeme 	mutex_exit(&sme_list_mtx);
547104f2a80Syamt 	return sme;
548e67f5e66Sthorpej }
549e67f5e66Sthorpej 
550e67f5e66Sthorpej /*
551e67f5e66Sthorpej  * sysmon_envsys_release:
552e67f5e66Sthorpej  *
553*bf4558f8Sxtraeme  * 	+ Release an envsys device.
554e67f5e66Sthorpej  */
555e67f5e66Sthorpej void
556e67f5e66Sthorpej sysmon_envsys_release(struct sysmon_envsys *sme)
557e67f5e66Sthorpej {
558*bf4558f8Sxtraeme 	mutex_enter(&sme_list_mtx);
55944d0d572Syamt 	if (sme->sme_flags & SME_FLAG_WANTED)
560*bf4558f8Sxtraeme 		cv_broadcast(&sme_list_cv);
56144d0d572Syamt 	sme->sme_flags &= ~(SME_FLAG_BUSY | SME_FLAG_WANTED);
562*bf4558f8Sxtraeme 	mutex_exit(&sme_list_mtx);
563*bf4558f8Sxtraeme }
564*bf4558f8Sxtraeme 
565*bf4558f8Sxtraeme /* compatibility function */
566*bf4558f8Sxtraeme #ifdef COMPAT_40
567*bf4558f8Sxtraeme struct sysmon_envsys *
568*bf4558f8Sxtraeme sysmon_envsys_find_40(u_int idx)
569*bf4558f8Sxtraeme {
570*bf4558f8Sxtraeme 	struct sysmon_envsys *sme;
571*bf4558f8Sxtraeme 
572*bf4558f8Sxtraeme 	mutex_enter(&sme_list_mtx);
573*bf4558f8Sxtraeme 	for (sme = LIST_FIRST(&sysmon_envsys_list); sme != NULL;
574*bf4558f8Sxtraeme 	     sme = LIST_NEXT(sme, sme_list)) {
575*bf4558f8Sxtraeme 		if (idx >= sme->sme_fsensor &&
576*bf4558f8Sxtraeme 	    	    idx < (sme->sme_fsensor + sme->sme_nsensors))
577*bf4558f8Sxtraeme 			break;
578*bf4558f8Sxtraeme 	}
579*bf4558f8Sxtraeme 	mutex_exit(&sme_list_mtx);
580*bf4558f8Sxtraeme 	return sme;
581*bf4558f8Sxtraeme }
582*bf4558f8Sxtraeme #endif
583*bf4558f8Sxtraeme 
584*bf4558f8Sxtraeme /*
585*bf4558f8Sxtraeme  * sysmon_envsys_createplist:
586*bf4558f8Sxtraeme  *
587*bf4558f8Sxtraeme  * 	+ Create the property list structure for a device.
588*bf4558f8Sxtraeme  */
589*bf4558f8Sxtraeme int
590*bf4558f8Sxtraeme sysmon_envsys_createplist(struct sysmon_envsys *sme)
591*bf4558f8Sxtraeme {
592*bf4558f8Sxtraeme 	envsys_data_t *edata;
593*bf4558f8Sxtraeme 	prop_array_t array;
594*bf4558f8Sxtraeme 	int i, error = 0;
595*bf4558f8Sxtraeme 
596*bf4558f8Sxtraeme 	/* create the sysmon envsys device array. */
597*bf4558f8Sxtraeme 	array = prop_array_create();
598*bf4558f8Sxtraeme 
599*bf4558f8Sxtraeme 	/*
600*bf4558f8Sxtraeme 	 * <dict>
601*bf4558f8Sxtraeme 	 * 	<key>foo0</key>
602*bf4558f8Sxtraeme 	 * 	<array>
603*bf4558f8Sxtraeme 	 * 		...
604*bf4558f8Sxtraeme 	 */
605*bf4558f8Sxtraeme 	mutex_enter(&sme_mtx);
606*bf4558f8Sxtraeme 	if (!prop_dictionary_set(sme_propd, sme->sme_name, array)) {
607*bf4558f8Sxtraeme 		DPRINTF(("%s: prop_dictionary_set\n", __func__));
608*bf4558f8Sxtraeme 		mutex_exit(&sme_mtx);
609*bf4558f8Sxtraeme 		error = EINVAL;
610*bf4558f8Sxtraeme 		goto out;
611*bf4558f8Sxtraeme 	}
612*bf4558f8Sxtraeme 	mutex_exit(&sme_mtx);
613*bf4558f8Sxtraeme 
614*bf4558f8Sxtraeme 	/*
615*bf4558f8Sxtraeme 	 * Iterate over all sensors and create a dictionary with all
616*bf4558f8Sxtraeme 	 * values specified by the sysmon envsys driver.
617*bf4558f8Sxtraeme 	 */
618*bf4558f8Sxtraeme 	for (i = 0; i < sme->sme_nsensors; i++) {
619*bf4558f8Sxtraeme 		edata = &sme->sme_sensor_data[i];
620*bf4558f8Sxtraeme 		/*
621*bf4558f8Sxtraeme 		 * refresh sensor data via sme_gtredata only if the
622*bf4558f8Sxtraeme 		 * flag is not set.
623*bf4558f8Sxtraeme 		 */
624*bf4558f8Sxtraeme 		if ((sme->sme_flags & SME_DISABLE_GTREDATA) == 0) {
625*bf4558f8Sxtraeme 			mutex_enter(&sme_mtx);
626*bf4558f8Sxtraeme 			error = (*sme->sme_gtredata)(sme, edata);
627*bf4558f8Sxtraeme 			if (error) {
628*bf4558f8Sxtraeme 				DPRINTF(("%s: sme->sme_gtredata[%d]\n",
629*bf4558f8Sxtraeme 				    __func__, i));
630*bf4558f8Sxtraeme 				mutex_exit(&sme_mtx);
631*bf4558f8Sxtraeme 				continue;
632*bf4558f8Sxtraeme 			}
633*bf4558f8Sxtraeme 			mutex_exit(&sme_mtx);
634*bf4558f8Sxtraeme 		}
635*bf4558f8Sxtraeme 
636*bf4558f8Sxtraeme 		error = sme_make_dictionary(sme, array, edata);
637*bf4558f8Sxtraeme 		if (error) {
638*bf4558f8Sxtraeme 			DPRINTF(("%s: sme_make_dictionary[%d]\n", __func__, i));
639*bf4558f8Sxtraeme 			goto out;
640*bf4558f8Sxtraeme 		}
641*bf4558f8Sxtraeme 	}
642*bf4558f8Sxtraeme 
643*bf4558f8Sxtraeme out:
644*bf4558f8Sxtraeme 	prop_object_release(array);
645*bf4558f8Sxtraeme 	return error;
646*bf4558f8Sxtraeme }
647*bf4558f8Sxtraeme 
648*bf4558f8Sxtraeme /*
649*bf4558f8Sxtraeme  * sme_make_dictionary:
650*bf4558f8Sxtraeme  *
651*bf4558f8Sxtraeme  * 	+ Create sensor's dictionary in device's dictionary array.
652*bf4558f8Sxtraeme  */
653*bf4558f8Sxtraeme int
654*bf4558f8Sxtraeme sme_make_dictionary(struct sysmon_envsys *sme, prop_array_t array,
655*bf4558f8Sxtraeme 		    envsys_data_t *edata)
656*bf4558f8Sxtraeme {
657*bf4558f8Sxtraeme 	const struct sme_sensor_type *est = sme_sensor_type;
658*bf4558f8Sxtraeme 	const struct sme_sensor_state *ess = sme_sensor_state;
659*bf4558f8Sxtraeme 	const struct sme_sensor_state *esds = sme_sensor_drive_state;
660*bf4558f8Sxtraeme 	sme_event_drv_t *sme_evdrv_t = NULL;
661*bf4558f8Sxtraeme 	prop_dictionary_t dict;
662*bf4558f8Sxtraeme 	int i, j, k;
663*bf4558f8Sxtraeme 
664*bf4558f8Sxtraeme 	i = j = k = 0;
665*bf4558f8Sxtraeme 
666*bf4558f8Sxtraeme 	/*
667*bf4558f8Sxtraeme 	 * <array>
668*bf4558f8Sxtraeme 	 * 	<dict>
669*bf4558f8Sxtraeme 	 * 		...
670*bf4558f8Sxtraeme 	 */
671*bf4558f8Sxtraeme 	dict = prop_dictionary_create();
672*bf4558f8Sxtraeme 
673*bf4558f8Sxtraeme 	mutex_enter(&sme_mtx);
674*bf4558f8Sxtraeme 	if (!prop_array_add(array, dict)) {
675*bf4558f8Sxtraeme 		mutex_exit(&sme_mtx);
676*bf4558f8Sxtraeme 		DPRINTF(("%s: prop_array_add\n", __func__));
677*bf4558f8Sxtraeme 		return EINVAL;
678*bf4558f8Sxtraeme 	}
679*bf4558f8Sxtraeme 
680*bf4558f8Sxtraeme 	/* find the correct unit for this sensor. */
681*bf4558f8Sxtraeme 	for (i = 0; est[i].type != -1; i++)
682*bf4558f8Sxtraeme 		if (est[i].type == edata->units)
683*bf4558f8Sxtraeme 			break;
684*bf4558f8Sxtraeme 
685*bf4558f8Sxtraeme 	/*
686*bf4558f8Sxtraeme 	 * 		...
687*bf4558f8Sxtraeme 	 * 		<key>type</key>
688*bf4558f8Sxtraeme 	 * 		<string>foo</string>
689*bf4558f8Sxtraeme 	 * 		<key>description</key>
690*bf4558f8Sxtraeme 	 * 		<string>blah blah</string>
691*bf4558f8Sxtraeme 	 * 		...
692*bf4558f8Sxtraeme 	 */
693*bf4558f8Sxtraeme 	SENSOR_SSTRING(dict, "type", est[i].desc);
694*bf4558f8Sxtraeme 	SENSOR_SSTRING(dict, "description", edata->desc);
695*bf4558f8Sxtraeme 
696*bf4558f8Sxtraeme 	/*
697*bf4558f8Sxtraeme 	 * Add sensor's state description.
698*bf4558f8Sxtraeme 	 *
699*bf4558f8Sxtraeme 	 * 		...
700*bf4558f8Sxtraeme 	 * 		<key>state</key>
701*bf4558f8Sxtraeme 	 * 		<string>valid</string>
702*bf4558f8Sxtraeme 	 * 		...
703*bf4558f8Sxtraeme 	 */
704*bf4558f8Sxtraeme 	for (j = 0; ess[j].type != -1; j++)
705*bf4558f8Sxtraeme 		if (ess[j].type == edata->state)
706*bf4558f8Sxtraeme 			break;
707*bf4558f8Sxtraeme 
708*bf4558f8Sxtraeme 	SENSOR_SSTRING(dict, "state", ess[j].desc);
709*bf4558f8Sxtraeme 
710*bf4558f8Sxtraeme 	/*
711*bf4558f8Sxtraeme 	 * add the percentage boolean object:
712*bf4558f8Sxtraeme 	 *
713*bf4558f8Sxtraeme 	 * 		...
714*bf4558f8Sxtraeme 	 * 		<key>want-percentage</key>
715*bf4558f8Sxtraeme 	 * 		<true/>
716*bf4558f8Sxtraeme 	 * 		...
717*bf4558f8Sxtraeme 	 */
718*bf4558f8Sxtraeme 	if (edata->flags & ENVSYS_FPERCENT)
719*bf4558f8Sxtraeme 		SENSOR_SBOOL(dict, "want-percentage", true);
720*bf4558f8Sxtraeme 
721*bf4558f8Sxtraeme 	/*
722*bf4558f8Sxtraeme 	 * Add the monitoring boolean object:
723*bf4558f8Sxtraeme 	 *
724*bf4558f8Sxtraeme 	 * 		...
725*bf4558f8Sxtraeme 	 * 		<key>monitoring-supported</key>
726*bf4558f8Sxtraeme 	 * 		<true/>
727*bf4558f8Sxtraeme 	 *		...
728*bf4558f8Sxtraeme 	 *
729*bf4558f8Sxtraeme 	 * always false on Drive, Integer and Indicator types, they
730*bf4558f8Sxtraeme 	 * cannot be monitored.
731*bf4558f8Sxtraeme 	 *
732*bf4558f8Sxtraeme 	 */
733*bf4558f8Sxtraeme 	if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
734*bf4558f8Sxtraeme 	    (edata->units == ENVSYS_INDICATOR) ||
735*bf4558f8Sxtraeme 	    (edata->units == ENVSYS_INTEGER) ||
736*bf4558f8Sxtraeme 	    (edata->units == ENVSYS_DRIVE)) {
737*bf4558f8Sxtraeme 		SENSOR_SBOOL(dict, "monitoring-supported", false);
738*bf4558f8Sxtraeme 	} else {
739*bf4558f8Sxtraeme 		SENSOR_SBOOL(dict, "monitoring-supported", true);
740*bf4558f8Sxtraeme 	}
741*bf4558f8Sxtraeme 
742*bf4558f8Sxtraeme 	/*
743*bf4558f8Sxtraeme 	 * Add the drive-state object for drive sensors:
744*bf4558f8Sxtraeme 	 *
745*bf4558f8Sxtraeme 	 * 		...
746*bf4558f8Sxtraeme 	 * 		<key>drive-state</key>
747*bf4558f8Sxtraeme 	 * 		<string>drive is online</string>
748*bf4558f8Sxtraeme 	 * 		...
749*bf4558f8Sxtraeme 	 */
750*bf4558f8Sxtraeme 	if (edata->units == ENVSYS_DRIVE) {
751*bf4558f8Sxtraeme 		for (k = 0; esds[k].type != -1; k++)
752*bf4558f8Sxtraeme 			if (esds[k].type == edata->value_cur)
753*bf4558f8Sxtraeme 				break;
754*bf4558f8Sxtraeme 		SENSOR_SSTRING(dict, "drive-state", esds[k].desc);
755*bf4558f8Sxtraeme 	}
756*bf4558f8Sxtraeme 
757*bf4558f8Sxtraeme 	mutex_exit(&sme_mtx);
758*bf4558f8Sxtraeme 	/*
759*bf4558f8Sxtraeme 	 * Add a new event if a monitoring flag was set.
760*bf4558f8Sxtraeme 	 */
761*bf4558f8Sxtraeme 	if (edata->monitor) {
762*bf4558f8Sxtraeme 		sme_evdrv_t = kmem_zalloc(sizeof(*sme_evdrv_t), KM_SLEEP);
763*bf4558f8Sxtraeme 
764*bf4558f8Sxtraeme 		sme_evdrv_t->sdict = dict;
765*bf4558f8Sxtraeme 		sme_evdrv_t->edata = edata;
766*bf4558f8Sxtraeme 		sme_evdrv_t->sme = sme;
767*bf4558f8Sxtraeme 		sme_evdrv_t->powertype = est[i].crittype;
768*bf4558f8Sxtraeme 
769*bf4558f8Sxtraeme 		sysmon_task_queue_init();
770*bf4558f8Sxtraeme 		sysmon_task_queue_sched(0, sme_event_drvadd, sme_evdrv_t);
771*bf4558f8Sxtraeme 	}
772*bf4558f8Sxtraeme 
773*bf4558f8Sxtraeme 	mutex_enter(&sme_mtx);
774*bf4558f8Sxtraeme 	/* if sensor is enabled, add the following properties... */
775*bf4558f8Sxtraeme 	if (edata->state == ENVSYS_SVALID) {
776*bf4558f8Sxtraeme 		/*
777*bf4558f8Sxtraeme 		 * 	...
778*bf4558f8Sxtraeme 		 * 	<key>rpms</key>
779*bf4558f8Sxtraeme 		 * 	<integer>2500</integer>
780*bf4558f8Sxtraeme 		 * 	<key>rfact</key>
781*bf4558f8Sxtraeme 		 * 	<integer>10000</integer>
782*bf4558f8Sxtraeme 		 * 	<key>cur-value</key>
783*bf4558f8Sxtraeme 		 * 	<integer>1250</integer>
784*bf4558f8Sxtraeme 		 * 	<key>min-value</key>
785*bf4558f8Sxtraeme 		 * 	<integer>800</integer>
786*bf4558f8Sxtraeme 		 * 	<key>max-value</integer>
787*bf4558f8Sxtraeme 		 * 	<integer>3000</integer>
788*bf4558f8Sxtraeme 		 * 	<key>avg-value</integer>
789*bf4558f8Sxtraeme 		 * 	<integer>1400</integer>
790*bf4558f8Sxtraeme 		 * </dict>
791*bf4558f8Sxtraeme 		 */
792*bf4558f8Sxtraeme 		if ((edata->units == ENVSYS_SFANRPM) && edata->rpms)
793*bf4558f8Sxtraeme 			SENSOR_SUINT32(dict, "rpms", edata->rpms);
794*bf4558f8Sxtraeme 
795*bf4558f8Sxtraeme 		if ((edata->units == ENVSYS_SVOLTS_AC ||
796*bf4558f8Sxtraeme 		    edata->units == ENVSYS_SVOLTS_DC) && edata->rfact)
797*bf4558f8Sxtraeme 			SENSOR_SINT32(dict, "rfact", edata->rfact);
798*bf4558f8Sxtraeme 
799*bf4558f8Sxtraeme 		if (edata->value_cur)
800*bf4558f8Sxtraeme 			SENSOR_SINT32(dict, "cur-value", edata->value_cur);
801*bf4558f8Sxtraeme 
802*bf4558f8Sxtraeme 		if ((edata->flags & ENVSYS_FVALID_MIN) && edata->value_min)
803*bf4558f8Sxtraeme 			SENSOR_SINT32(dict, "min-value", edata->value_min);
804*bf4558f8Sxtraeme 
805*bf4558f8Sxtraeme 		if ((edata->flags & ENVSYS_FVALID_MAX) && edata->value_max)
806*bf4558f8Sxtraeme 			SENSOR_SINT32(dict, "max-value", edata->value_max);
807*bf4558f8Sxtraeme 
808*bf4558f8Sxtraeme 		if ((edata->flags & ENVSYS_FVALID_AVG) && edata->value_avg)
809*bf4558f8Sxtraeme 			SENSOR_SINT32(dict, "avg-value", edata->value_avg);
810*bf4558f8Sxtraeme 	}
811*bf4558f8Sxtraeme 
812*bf4558f8Sxtraeme 	/*
813*bf4558f8Sxtraeme 	 * 	...
814*bf4558f8Sxtraeme 	 * </array>
815*bf4558f8Sxtraeme 	 */
816*bf4558f8Sxtraeme out:
817*bf4558f8Sxtraeme 	mutex_exit(&sme_mtx);
818*bf4558f8Sxtraeme 	prop_object_release(dict);
819*bf4558f8Sxtraeme 	return 0;
820*bf4558f8Sxtraeme }
821*bf4558f8Sxtraeme 
822*bf4558f8Sxtraeme /*
823*bf4558f8Sxtraeme  * sme_update_dictionary:
824*bf4558f8Sxtraeme  *
825*bf4558f8Sxtraeme  * 	+ Update per-sensor dictionaries with new values if there were
826*bf4558f8Sxtraeme  * 	  changes, otherwise the object in dictionary is untouched.
827*bf4558f8Sxtraeme  * 	+ Send a critical event if any sensor is in a critical condition.
828*bf4558f8Sxtraeme  */
829*bf4558f8Sxtraeme int
830*bf4558f8Sxtraeme sme_update_dictionary(struct sysmon_envsys *sme)
831*bf4558f8Sxtraeme {
832*bf4558f8Sxtraeme 	const struct sme_sensor_state *ess = sme_sensor_state;
833*bf4558f8Sxtraeme 	const struct sme_sensor_state *esds = sme_sensor_drive_state;
834*bf4558f8Sxtraeme 	envsys_data_t *edata = NULL;
835*bf4558f8Sxtraeme 	prop_object_t array, obj, dict = NULL;
836*bf4558f8Sxtraeme 	int i, j, error = 0;
837*bf4558f8Sxtraeme 
838*bf4558f8Sxtraeme 	/* retrieve the array of dictionaries in device. */
839*bf4558f8Sxtraeme 	array = prop_dictionary_get(sme_propd, sme->sme_name);
840*bf4558f8Sxtraeme 	if (prop_object_type(array) != PROP_TYPE_ARRAY)
841*bf4558f8Sxtraeme 		return EINVAL;
842*bf4558f8Sxtraeme 
843*bf4558f8Sxtraeme 	/*
844*bf4558f8Sxtraeme 	 * - iterate over all sensors.
845*bf4558f8Sxtraeme 	 * - fetch new data.
846*bf4558f8Sxtraeme 	 * - check if data in dictionary is different than new data.
847*bf4558f8Sxtraeme 	 * - update dictionary if there were changes.
848*bf4558f8Sxtraeme 	 */
849*bf4558f8Sxtraeme 	for (i = 0; i < sme->sme_nsensors; i++) {
850*bf4558f8Sxtraeme 		edata = &sme->sme_sensor_data[i];
851*bf4558f8Sxtraeme 
852*bf4558f8Sxtraeme 		/*
853*bf4558f8Sxtraeme 		 * refresh sensor data via sme_gtredata only if the
854*bf4558f8Sxtraeme 		 * flag is not set.
855*bf4558f8Sxtraeme 		 */
856*bf4558f8Sxtraeme 		if ((sme->sme_flags & SME_DISABLE_GTREDATA) == 0) {
857*bf4558f8Sxtraeme 			error = (*sme->sme_gtredata)(sme, edata);
858*bf4558f8Sxtraeme 			if (error) {
859*bf4558f8Sxtraeme 				DPRINTF(("%s: gtredata[%d] failed\n",
860*bf4558f8Sxtraeme 				    __func__, i));
861*bf4558f8Sxtraeme 				return error;
862*bf4558f8Sxtraeme 			}
863*bf4558f8Sxtraeme 		}
864*bf4558f8Sxtraeme 
865*bf4558f8Sxtraeme 		/* retrieve sensor's dictionary. */
866*bf4558f8Sxtraeme 		dict = prop_array_get(array, i);
867*bf4558f8Sxtraeme 		if (prop_object_type(dict) != PROP_TYPE_DICTIONARY)
868*bf4558f8Sxtraeme 			return EINVAL;
869*bf4558f8Sxtraeme 
870*bf4558f8Sxtraeme 		/* update state sensor. */
871*bf4558f8Sxtraeme 		for (j = 0; ess[j].type != -1; j++)
872*bf4558f8Sxtraeme 			if (ess[j].type == edata->state)
873*bf4558f8Sxtraeme 				break;
874*bf4558f8Sxtraeme 
875*bf4558f8Sxtraeme 		DPRINTFOBJ(("%s: state=%s type=%d flags=%d "
876*bf4558f8Sxtraeme 		    "units=%d sensor=%d\n", __func__, ess[j].desc,
877*bf4558f8Sxtraeme 		    ess[j].type, edata->flags, edata->units, edata->sensor));
878*bf4558f8Sxtraeme 
879*bf4558f8Sxtraeme 		/* update sensor state */
880*bf4558f8Sxtraeme 		SENSOR_UPSTRING(dict, "state", ess[j].desc);
881*bf4558f8Sxtraeme 
882*bf4558f8Sxtraeme 		/* update sensor current value */
883*bf4558f8Sxtraeme 		SENSOR_UPINT32(dict, "cur-value", edata->value_cur);
884*bf4558f8Sxtraeme 
885*bf4558f8Sxtraeme 		/*
886*bf4558f8Sxtraeme 		 * Integer and Indicator types do not the following
887*bf4558f8Sxtraeme 		 * values, so skip them.
888*bf4558f8Sxtraeme 		 */
889*bf4558f8Sxtraeme 		if (edata->units == ENVSYS_INTEGER ||
890*bf4558f8Sxtraeme 		    edata->units == ENVSYS_INDICATOR)
891*bf4558f8Sxtraeme 			continue;
892*bf4558f8Sxtraeme 
893*bf4558f8Sxtraeme 		/* update sensor flags */
894*bf4558f8Sxtraeme 		if (edata->flags & ENVSYS_FPERCENT)
895*bf4558f8Sxtraeme 			SENSOR_SBOOL(dict, "want-percentage", true);
896*bf4558f8Sxtraeme 		else {
897*bf4558f8Sxtraeme 			obj = prop_dictionary_get(dict, "want-percentage");
898*bf4558f8Sxtraeme 			if (obj)
899*bf4558f8Sxtraeme 				SENSOR_SBOOL(dict, "want-percentage", false);
900*bf4558f8Sxtraeme 		}
901*bf4558f8Sxtraeme 
902*bf4558f8Sxtraeme 		if (edata->flags & ENVSYS_FVALID_MAX)
903*bf4558f8Sxtraeme 			SENSOR_UPINT32(dict, "max-value", edata->value_max);
904*bf4558f8Sxtraeme 
905*bf4558f8Sxtraeme 		if (edata->flags & ENVSYS_FVALID_MIN)
906*bf4558f8Sxtraeme 			SENSOR_UPINT32(dict, "min-value", edata->value_min);
907*bf4558f8Sxtraeme 
908*bf4558f8Sxtraeme 		if (edata->flags & ENVSYS_FVALID_AVG)
909*bf4558f8Sxtraeme 			SENSOR_UPINT32(dict, "avg-value", edata->value_avg);
910*bf4558f8Sxtraeme 
911*bf4558f8Sxtraeme 		/* update 'rpms' only in ENVSYS_SFANRPM. */
912*bf4558f8Sxtraeme 		if (edata->units == ENVSYS_SFANRPM)
913*bf4558f8Sxtraeme 			SENSOR_UPUINT32(dict, "rpms", edata->rpms);
914*bf4558f8Sxtraeme 
915*bf4558f8Sxtraeme 		/* update 'rfact' only in ENVSYS_SVOLTS_[AD]C. */
916*bf4558f8Sxtraeme 		if (edata->units == ENVSYS_SVOLTS_AC ||
917*bf4558f8Sxtraeme 		    edata->units == ENVSYS_SVOLTS_DC) {
918*bf4558f8Sxtraeme 			SENSOR_UPINT32(dict, "rfact", edata->rfact);
919*bf4558f8Sxtraeme 		}
920*bf4558f8Sxtraeme 
921*bf4558f8Sxtraeme 		/* update 'drive-state' only in ENVSYS_DRIVE. */
922*bf4558f8Sxtraeme 		if (edata->units == ENVSYS_DRIVE) {
923*bf4558f8Sxtraeme 			for (j = 0; esds[j].type != -1; j++)
924*bf4558f8Sxtraeme 				if (esds[j].type == edata->value_cur)
925*bf4558f8Sxtraeme 					break;
926*bf4558f8Sxtraeme 
927*bf4558f8Sxtraeme 			SENSOR_UPSTRING(dict, "drive-state", esds[j].desc);
928*bf4558f8Sxtraeme 		}
929*bf4558f8Sxtraeme 	}
930*bf4558f8Sxtraeme 
931*bf4558f8Sxtraeme out:
932*bf4558f8Sxtraeme 	return error;
933*bf4558f8Sxtraeme }
934*bf4558f8Sxtraeme 
935*bf4558f8Sxtraeme /*
936*bf4558f8Sxtraeme  * sme_userset_dictionary:
937*bf4558f8Sxtraeme  *
938*bf4558f8Sxtraeme  * 	+ Parses the userland dictionary and run the appropiate
939*bf4558f8Sxtraeme  * 	  tasks that were requested.
940*bf4558f8Sxtraeme  */
941*bf4558f8Sxtraeme int
942*bf4558f8Sxtraeme sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
943*bf4558f8Sxtraeme 		       prop_array_t array)
944*bf4558f8Sxtraeme {
945*bf4558f8Sxtraeme 	const struct sme_sensor_type *sst = sme_sensor_type;
946*bf4558f8Sxtraeme 	envsys_data_t *edata;
947*bf4558f8Sxtraeme 	prop_dictionary_t dict;
948*bf4558f8Sxtraeme 	prop_object_t obj, obj1, obj2;
949*bf4558f8Sxtraeme 	int32_t critval;
950*bf4558f8Sxtraeme 	int i, error = 0;
951*bf4558f8Sxtraeme 	const char *blah, *sname;
952*bf4558f8Sxtraeme 	bool targetfound = false;
953*bf4558f8Sxtraeme 
954*bf4558f8Sxtraeme 	blah = sname = NULL;
955*bf4558f8Sxtraeme 
956*bf4558f8Sxtraeme 	/* get sensor's name from userland dictionary. */
957*bf4558f8Sxtraeme 	obj = prop_dictionary_get(udict, "sensor-name");
958*bf4558f8Sxtraeme 	if (prop_object_type(obj) != PROP_TYPE_STRING) {
959*bf4558f8Sxtraeme 		DPRINTF(("%s: sensor-name failed\n", __func__));
960*bf4558f8Sxtraeme 		return EINVAL;
961*bf4558f8Sxtraeme 	}
962*bf4558f8Sxtraeme 
963*bf4558f8Sxtraeme 	/* iterate over the sensors to find the right one */
964*bf4558f8Sxtraeme 	for (i = 0; i < sme->sme_nsensors; i++) {
965*bf4558f8Sxtraeme 		edata = &sme->sme_sensor_data[i];
966*bf4558f8Sxtraeme 		dict = prop_array_get(array, i);
967*bf4558f8Sxtraeme 		obj1 = prop_dictionary_get(dict, "description");
968*bf4558f8Sxtraeme 
969*bf4558f8Sxtraeme 		/* is it our sensor? */
970*bf4558f8Sxtraeme 		if (!prop_string_equals(obj1, obj))
971*bf4558f8Sxtraeme 			continue;
972*bf4558f8Sxtraeme 
973*bf4558f8Sxtraeme 		/*
974*bf4558f8Sxtraeme 		 * Check if a new description operation was
975*bf4558f8Sxtraeme 		 * requested by the user and set new description.
976*bf4558f8Sxtraeme 		 */
977*bf4558f8Sxtraeme 		if ((obj2 = prop_dictionary_get(udict, "new-description"))) {
978*bf4558f8Sxtraeme 			targetfound = true;
979*bf4558f8Sxtraeme 			blah = prop_string_cstring_nocopy(obj2);
980*bf4558f8Sxtraeme 			SENSOR_UPSTRING(dict, "description", blah);
981*bf4558f8Sxtraeme 			break;
982*bf4558f8Sxtraeme 		}
983*bf4558f8Sxtraeme 
984*bf4558f8Sxtraeme 		/* did the user want to remove a critical capacity limit? */
985*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "remove-critical-cap");
986*bf4558f8Sxtraeme 		if (obj2 != NULL) {
987*bf4558f8Sxtraeme 			targetfound = true;
988*bf4558f8Sxtraeme 			if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
989*bf4558f8Sxtraeme 			    (edata->flags & ENVSYS_FPERCENT) == 0) {
990*bf4558f8Sxtraeme 				    error = ENOTSUP;
991*bf4558f8Sxtraeme 				    break;
992*bf4558f8Sxtraeme 			}
993*bf4558f8Sxtraeme 
994*bf4558f8Sxtraeme 			sname = prop_string_cstring_nocopy(obj);
995*bf4558f8Sxtraeme 			error = sme_event_unregister(sname,
996*bf4558f8Sxtraeme 			    PENVSYS_EVENT_BATT_USERCAP);
997*bf4558f8Sxtraeme 			if (error)
998*bf4558f8Sxtraeme 				break;
999*bf4558f8Sxtraeme 
1000*bf4558f8Sxtraeme 			prop_dictionary_remove(dict, "critical-capacity");
1001*bf4558f8Sxtraeme 			break;
1002*bf4558f8Sxtraeme 		}
1003*bf4558f8Sxtraeme 
1004*bf4558f8Sxtraeme 		/* did the user want to remove a critical min limit? */
1005*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "remove-cmin-limit");
1006*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1007*bf4558f8Sxtraeme 			targetfound = true;
1008*bf4558f8Sxtraeme 			sname = prop_string_cstring_nocopy(obj);
1009*bf4558f8Sxtraeme 			error = sme_event_unregister(sname,
1010*bf4558f8Sxtraeme 			    PENVSYS_EVENT_USER_CRITMIN);
1011*bf4558f8Sxtraeme 			if (error)
1012*bf4558f8Sxtraeme 				break;
1013*bf4558f8Sxtraeme 
1014*bf4558f8Sxtraeme 			prop_dictionary_remove(dict, "critical-min-limit");
1015*bf4558f8Sxtraeme 			break;
1016*bf4558f8Sxtraeme 		}
1017*bf4558f8Sxtraeme 
1018*bf4558f8Sxtraeme 		/* did the user want to remove a critical max limit? */
1019*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "remove-cmax-limit");
1020*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1021*bf4558f8Sxtraeme 			targetfound = true;
1022*bf4558f8Sxtraeme 			sname = prop_string_cstring_nocopy(obj);
1023*bf4558f8Sxtraeme 			error = sme_event_unregister(sname,
1024*bf4558f8Sxtraeme 			    PENVSYS_EVENT_USER_CRITMAX);
1025*bf4558f8Sxtraeme 			if (error)
1026*bf4558f8Sxtraeme 				break;
1027*bf4558f8Sxtraeme 
1028*bf4558f8Sxtraeme 			prop_dictionary_remove(dict, "critical-max-limit");
1029*bf4558f8Sxtraeme 			break;
1030*bf4558f8Sxtraeme 		}
1031*bf4558f8Sxtraeme 
1032*bf4558f8Sxtraeme 		/* did the user want to change rfact? */
1033*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "new-rfact");
1034*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1035*bf4558f8Sxtraeme 			targetfound = true;
1036*bf4558f8Sxtraeme 			if (edata->flags & ENVSYS_FCHANGERFACT)
1037*bf4558f8Sxtraeme 				edata->rfact = prop_number_integer_value(obj2);
1038*bf4558f8Sxtraeme 			else
1039*bf4558f8Sxtraeme 				error = ENOTSUP;
1040*bf4558f8Sxtraeme 
1041*bf4558f8Sxtraeme 			break;
1042*bf4558f8Sxtraeme 		}
1043*bf4558f8Sxtraeme 
1044*bf4558f8Sxtraeme 		for (i = 0; sst[i].type != -1; i++)
1045*bf4558f8Sxtraeme 			if (sst[i].type == edata->units)
1046*bf4558f8Sxtraeme 				break;
1047*bf4558f8Sxtraeme 
1048*bf4558f8Sxtraeme 		/* did the user want to set a critical capacity event? */
1049*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "critical-capacity");
1050*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1051*bf4558f8Sxtraeme 			targetfound = true;
1052*bf4558f8Sxtraeme 			if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
1053*bf4558f8Sxtraeme 			    (edata->flags & ENVSYS_FPERCENT) == 0) {
1054*bf4558f8Sxtraeme 				error = ENOTSUP;
1055*bf4558f8Sxtraeme 				break;
1056*bf4558f8Sxtraeme 			}
1057*bf4558f8Sxtraeme 
1058*bf4558f8Sxtraeme 			critval = prop_number_integer_value(obj2);
1059*bf4558f8Sxtraeme 			error = sme_event_add(dict,
1060*bf4558f8Sxtraeme 					      edata,
1061*bf4558f8Sxtraeme 					      sme->sme_name,
1062*bf4558f8Sxtraeme 					      "critical-capacity",
1063*bf4558f8Sxtraeme 					      critval,
1064*bf4558f8Sxtraeme 					      PENVSYS_EVENT_BATT_USERCAP,
1065*bf4558f8Sxtraeme 					      sst[i].crittype);
1066*bf4558f8Sxtraeme 			break;
1067*bf4558f8Sxtraeme 		}
1068*bf4558f8Sxtraeme 
1069*bf4558f8Sxtraeme 		/* did the user want to set a critical max event? */
1070*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "critical-max-limit");
1071*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1072*bf4558f8Sxtraeme 			targetfound = true;
1073*bf4558f8Sxtraeme 			if (edata->units == ENVSYS_INDICATOR ||
1074*bf4558f8Sxtraeme 			    edata->units == ENVSYS_INTEGER ||
1075*bf4558f8Sxtraeme 			    edata->flags & ENVSYS_FMONNOTSUPP) {
1076*bf4558f8Sxtraeme 				error = ENOTSUP;
1077*bf4558f8Sxtraeme 				break;
1078*bf4558f8Sxtraeme 			}
1079*bf4558f8Sxtraeme 
1080*bf4558f8Sxtraeme 			critval = prop_number_integer_value(obj2);
1081*bf4558f8Sxtraeme 			error = sme_event_add(dict,
1082*bf4558f8Sxtraeme 					      edata,
1083*bf4558f8Sxtraeme 					      sme->sme_name,
1084*bf4558f8Sxtraeme 					      "critical-max-limit",
1085*bf4558f8Sxtraeme 					      critval,
1086*bf4558f8Sxtraeme 					      PENVSYS_EVENT_USER_CRITMAX,
1087*bf4558f8Sxtraeme 					      sst[i].crittype);
1088*bf4558f8Sxtraeme 			break;
1089*bf4558f8Sxtraeme 		}
1090*bf4558f8Sxtraeme 
1091*bf4558f8Sxtraeme 		/* did the user want to set a critical min event? */
1092*bf4558f8Sxtraeme 		obj2 = prop_dictionary_get(udict, "critical-min-limit");
1093*bf4558f8Sxtraeme 		if (obj2 != NULL) {
1094*bf4558f8Sxtraeme 			targetfound = true;
1095*bf4558f8Sxtraeme 			if (edata->units == ENVSYS_INDICATOR ||
1096*bf4558f8Sxtraeme 			    edata->units == ENVSYS_INTEGER ||
1097*bf4558f8Sxtraeme 			    edata->flags & ENVSYS_FMONNOTSUPP) {
1098*bf4558f8Sxtraeme 				error = ENOTSUP;
1099*bf4558f8Sxtraeme 				break;
1100*bf4558f8Sxtraeme 			}
1101*bf4558f8Sxtraeme 
1102*bf4558f8Sxtraeme 			critval = prop_number_integer_value(obj2);
1103*bf4558f8Sxtraeme 			error = sme_event_add(dict,
1104*bf4558f8Sxtraeme 					      edata,
1105*bf4558f8Sxtraeme 					      sme->sme_name,
1106*bf4558f8Sxtraeme 					      "critical-min-limit",
1107*bf4558f8Sxtraeme 					      critval,
1108*bf4558f8Sxtraeme 					      PENVSYS_EVENT_USER_CRITMIN,
1109*bf4558f8Sxtraeme 					      sst[i].crittype);
1110*bf4558f8Sxtraeme 			break;
1111*bf4558f8Sxtraeme 		}
1112*bf4558f8Sxtraeme 	}
1113*bf4558f8Sxtraeme 
1114*bf4558f8Sxtraeme 	/* invalid target? return the error */
1115*bf4558f8Sxtraeme 	if (!targetfound)
1116*bf4558f8Sxtraeme 		error = EINVAL;
1117*bf4558f8Sxtraeme 
1118*bf4558f8Sxtraeme out:
1119*bf4558f8Sxtraeme 	return error;
1120e67f5e66Sthorpej }
1121