1*9f981eecSandvar /* $NetBSD: sysmon_envsys.c,v 1.151 2022/05/20 21:31:24 andvar Exp $ */
2bf4558f8Sxtraeme
3bf4558f8Sxtraeme /*-
4a826e85aSxtraeme * Copyright (c) 2007, 2008 Juan Romero Pardines.
5bf4558f8Sxtraeme * All rights reserved.
6bf4558f8Sxtraeme *
7bf4558f8Sxtraeme * Redistribution and use in source and binary forms, with or without
8bf4558f8Sxtraeme * modification, are permitted provided that the following conditions
9bf4558f8Sxtraeme * are met:
10bf4558f8Sxtraeme * 1. Redistributions of source code must retain the above copyright
11bf4558f8Sxtraeme * notice, this list of conditions and the following disclaimer.
12bf4558f8Sxtraeme * 2. Redistributions in binary form must reproduce the above copyright
13bf4558f8Sxtraeme * notice, this list of conditions and the following disclaimer in the
14bf4558f8Sxtraeme * documentation and/or other materials provided with the distribution.
15bf4558f8Sxtraeme *
166c4da82bSxtraeme * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
176c4da82bSxtraeme * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
186c4da82bSxtraeme * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
196c4da82bSxtraeme * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
206c4da82bSxtraeme * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
216c4da82bSxtraeme * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
226c4da82bSxtraeme * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
236c4da82bSxtraeme * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
246c4da82bSxtraeme * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
256c4da82bSxtraeme * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26bf4558f8Sxtraeme */
27e67f5e66Sthorpej
28e67f5e66Sthorpej /*-
29e67f5e66Sthorpej * Copyright (c) 2000 Zembu Labs, Inc.
30e67f5e66Sthorpej * All rights reserved.
31e67f5e66Sthorpej *
32e67f5e66Sthorpej * Author: Jason R. Thorpe <thorpej@zembu.com>
33e67f5e66Sthorpej *
34e67f5e66Sthorpej * Redistribution and use in source and binary forms, with or without
35e67f5e66Sthorpej * modification, are permitted provided that the following conditions
36e67f5e66Sthorpej * are met:
37e67f5e66Sthorpej * 1. Redistributions of source code must retain the above copyright
38e67f5e66Sthorpej * notice, this list of conditions and the following disclaimer.
39e67f5e66Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
40e67f5e66Sthorpej * notice, this list of conditions and the following disclaimer in the
41e67f5e66Sthorpej * documentation and/or other materials provided with the distribution.
42e67f5e66Sthorpej * 3. All advertising materials mentioning features or use of this software
43e67f5e66Sthorpej * must display the following acknowledgement:
44e67f5e66Sthorpej * This product includes software developed by Zembu Labs, Inc.
45e67f5e66Sthorpej * 4. Neither the name of Zembu Labs nor the names of its employees may
46e67f5e66Sthorpej * be used to endorse or promote products derived from this software
47e67f5e66Sthorpej * without specific prior written permission.
48e67f5e66Sthorpej *
49e67f5e66Sthorpej * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
50e67f5e66Sthorpej * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
51e67f5e66Sthorpej * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
52e67f5e66Sthorpej * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
53e67f5e66Sthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
54e67f5e66Sthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55e67f5e66Sthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56e67f5e66Sthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57e67f5e66Sthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
58e67f5e66Sthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59e67f5e66Sthorpej */
60e67f5e66Sthorpej
61e67f5e66Sthorpej /*
62bf4558f8Sxtraeme * Environmental sensor framework for sysmon, exported to userland
63bf4558f8Sxtraeme * with proplib(3).
64e67f5e66Sthorpej */
65e67f5e66Sthorpej
66640249d1Slukem #include <sys/cdefs.h>
67*9f981eecSandvar __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.151 2022/05/20 21:31:24 andvar Exp $");
68640249d1Slukem
69e67f5e66Sthorpej #include <sys/param.h>
70bf4558f8Sxtraeme #include <sys/types.h>
71e67f5e66Sthorpej #include <sys/conf.h>
72e67f5e66Sthorpej #include <sys/errno.h>
730a6f85e0Sxtraeme #include <sys/fcntl.h>
74e67f5e66Sthorpej #include <sys/kernel.h>
75e67f5e66Sthorpej #include <sys/systm.h>
76e67f5e66Sthorpej #include <sys/proc.h>
77bf4558f8Sxtraeme #include <sys/mutex.h>
78bf4558f8Sxtraeme #include <sys/kmem.h>
79233f556cSriastradh #include <sys/rndsource.h>
808061eedeSpgoyette #include <sys/module.h>
81eb659e13Spgoyette #include <sys/once.h>
82e67f5e66Sthorpej
83e67f5e66Sthorpej #include <dev/sysmon/sysmonvar.h>
84bf4558f8Sxtraeme #include <dev/sysmon/sysmon_envsysvar.h>
85bf4558f8Sxtraeme #include <dev/sysmon/sysmon_taskq.h>
86bf4558f8Sxtraeme
875ee4eba8Sxtraeme kmutex_t sme_global_mtx;
88666d1545Sxtraeme
896d6a3099Spgoyette prop_dictionary_t sme_propd;
906d6a3099Spgoyette
91a621c894Smatt struct sysmon_envsys_lh sysmon_envsys_list;
92a621c894Smatt
935ee4eba8Sxtraeme static uint32_t sysmon_envsys_next_sensor_index;
94bf4558f8Sxtraeme static struct sysmon_envsys *sysmon_envsys_find_40(u_int);
95bf4558f8Sxtraeme
96e83dd230Sxtraeme static void sysmon_envsys_destroy_plist(prop_array_t);
976c4da82bSxtraeme static void sme_remove_userprops(void);
9831962fc6Sxtraeme static int sme_add_property_dictionary(struct sysmon_envsys *, prop_array_t,
9931962fc6Sxtraeme prop_dictionary_t);
100d5f3dc8bSpgoyette static sme_event_drv_t * sme_add_sensor_dictionary(struct sysmon_envsys *,
101d5f3dc8bSpgoyette prop_array_t, prop_dictionary_t, envsys_data_t *);
102a826e85aSxtraeme static void sme_initial_refresh(void *);
103889f82ddSmartin static uint32_t sme_get_max_value(struct sysmon_envsys *,
104889f82ddSmartin bool (*)(const envsys_data_t*), bool);
105bf4558f8Sxtraeme
106142f2b40Spgoyette MODULE(MODULE_CLASS_DRIVER, sysmon_envsys, "sysmon,sysmon_taskq,sysmon_power");
1078061eedeSpgoyette
1088061eedeSpgoyette static struct sysmon_opvec sysmon_envsys_opvec = {
1098061eedeSpgoyette sysmonopen_envsys, sysmonclose_envsys, sysmonioctl_envsys,
1108061eedeSpgoyette NULL, NULL, NULL
1118061eedeSpgoyette };
1128061eedeSpgoyette
113eb659e13Spgoyette ONCE_DECL(once_envsys);
114eb659e13Spgoyette
115eb659e13Spgoyette static int
sme_preinit(void)116d3160376Schristos sme_preinit(void)
117d3160376Schristos {
118d3160376Schristos
119d3160376Schristos LIST_INIT(&sysmon_envsys_list);
120d3160376Schristos mutex_init(&sme_global_mtx, MUTEX_DEFAULT, IPL_NONE);
121d3160376Schristos sme_propd = prop_dictionary_create();
122eb659e13Spgoyette
123eb659e13Spgoyette return 0;
124d3160376Schristos }
125d3160376Schristos
126e67f5e66Sthorpej /*
127bf4558f8Sxtraeme * sysmon_envsys_init:
128bf4558f8Sxtraeme *
1295ee4eba8Sxtraeme * + Initialize global mutex, dictionary and the linked list.
130e67f5e66Sthorpej */
1318061eedeSpgoyette int
sysmon_envsys_init(void)132bf4558f8Sxtraeme sysmon_envsys_init(void)
133bf4558f8Sxtraeme {
1348061eedeSpgoyette int error;
1358061eedeSpgoyette
136eb659e13Spgoyette (void)RUN_ONCE(&once_envsys, sme_preinit);
1378061eedeSpgoyette
1388061eedeSpgoyette error = sysmon_attach_minor(SYSMON_MINOR_ENVSYS, &sysmon_envsys_opvec);
1398061eedeSpgoyette
1408061eedeSpgoyette return error;
1418061eedeSpgoyette }
1428061eedeSpgoyette
1438061eedeSpgoyette int
sysmon_envsys_fini(void)1448061eedeSpgoyette sysmon_envsys_fini(void)
1458061eedeSpgoyette {
1468061eedeSpgoyette int error;
1478061eedeSpgoyette
1488061eedeSpgoyette if ( ! LIST_EMPTY(&sysmon_envsys_list))
1498061eedeSpgoyette error = EBUSY;
1508061eedeSpgoyette else
1518061eedeSpgoyette error = sysmon_attach_minor(SYSMON_MINOR_ENVSYS, NULL);
1528061eedeSpgoyette
1538061eedeSpgoyette if (error == 0)
1548061eedeSpgoyette mutex_destroy(&sme_global_mtx);
1558061eedeSpgoyette
156d3160376Schristos // XXX: prop_dictionary ???
157d3160376Schristos
1588061eedeSpgoyette return error;
159bf4558f8Sxtraeme }
160e67f5e66Sthorpej
161e67f5e66Sthorpej /*
162e67f5e66Sthorpej * sysmonopen_envsys:
163e67f5e66Sthorpej *
164bf4558f8Sxtraeme * + Open the system monitor device.
165e67f5e66Sthorpej */
166e67f5e66Sthorpej int
sysmonopen_envsys(dev_t dev,int flag,int mode,struct lwp * l)167bf4558f8Sxtraeme sysmonopen_envsys(dev_t dev, int flag, int mode, struct lwp *l)
168e67f5e66Sthorpej {
169bf4558f8Sxtraeme return 0;
170e67f5e66Sthorpej }
171e67f5e66Sthorpej
172e67f5e66Sthorpej /*
173e67f5e66Sthorpej * sysmonclose_envsys:
174e67f5e66Sthorpej *
175bf4558f8Sxtraeme * + Close the system monitor device.
176e67f5e66Sthorpej */
177e67f5e66Sthorpej int
sysmonclose_envsys(dev_t dev,int flag,int mode,struct lwp * l)178bf4558f8Sxtraeme sysmonclose_envsys(dev_t dev, int flag, int mode, struct lwp *l)
179e67f5e66Sthorpej {
180bf4558f8Sxtraeme return 0;
181e67f5e66Sthorpej }
182e67f5e66Sthorpej
183e67f5e66Sthorpej /*
184e67f5e66Sthorpej * sysmonioctl_envsys:
185e67f5e66Sthorpej *
18663f1decdSxtraeme * + Perform a sysmon envsys control request.
187e67f5e66Sthorpej */
188e67f5e66Sthorpej int
sysmonioctl_envsys(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)189bf4558f8Sxtraeme sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
190e67f5e66Sthorpej {
191bf4558f8Sxtraeme struct sysmon_envsys *sme = NULL;
192e67f5e66Sthorpej int error = 0;
193e67f5e66Sthorpej u_int oidx;
194e67f5e66Sthorpej
195e67f5e66Sthorpej switch (cmd) {
19631962fc6Sxtraeme /*
19731962fc6Sxtraeme * To update the global dictionary with latest data from devices.
19831962fc6Sxtraeme */
199bf4558f8Sxtraeme case ENVSYS_GETDICTIONARY:
200e67f5e66Sthorpej {
201bf4558f8Sxtraeme struct plistref *plist = (struct plistref *)data;
20259e0238fSexplorer
203bf4558f8Sxtraeme /*
20431962fc6Sxtraeme * Update dictionaries on all sysmon envsys devices
20531962fc6Sxtraeme * registered.
206bf4558f8Sxtraeme */
2075ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
208bf4558f8Sxtraeme LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
2095ee4eba8Sxtraeme sysmon_envsys_acquire(sme, false);
210bf4558f8Sxtraeme error = sme_update_dictionary(sme);
211bf4558f8Sxtraeme if (error) {
212bf4558f8Sxtraeme DPRINTF(("%s: sme_update_dictionary, "
213bf4558f8Sxtraeme "error=%d\n", __func__, error));
2145ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
2155ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
216bf4558f8Sxtraeme return error;
217bf4558f8Sxtraeme }
2185ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
21982313816Sxtraeme }
2205ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
221bf4558f8Sxtraeme /*
222bf4558f8Sxtraeme * Copy global dictionary to userland.
223bf4558f8Sxtraeme */
224bf4558f8Sxtraeme error = prop_dictionary_copyout_ioctl(plist, cmd, sme_propd);
225bf4558f8Sxtraeme break;
226bf4558f8Sxtraeme }
22731962fc6Sxtraeme /*
22831962fc6Sxtraeme * To set properties on multiple devices.
22931962fc6Sxtraeme */
230bf4558f8Sxtraeme case ENVSYS_SETDICTIONARY:
231bf4558f8Sxtraeme {
232bf4558f8Sxtraeme const struct plistref *plist = (const struct plistref *)data;
233bf4558f8Sxtraeme prop_dictionary_t udict;
2346c4da82bSxtraeme prop_object_iterator_t iter, iter2;
2356c4da82bSxtraeme prop_object_t obj, obj2;
2366c4da82bSxtraeme prop_array_t array_u, array_k;
237bf4558f8Sxtraeme const char *devname = NULL;
23859e0238fSexplorer
2390a6f85e0Sxtraeme if ((flag & FWRITE) == 0)
2400a6f85e0Sxtraeme return EPERM;
2410a6f85e0Sxtraeme
242bf4558f8Sxtraeme /*
243bf4558f8Sxtraeme * Get dictionary from userland.
244bf4558f8Sxtraeme */
245bf4558f8Sxtraeme error = prop_dictionary_copyin_ioctl(plist, cmd, &udict);
246666d1545Sxtraeme if (error) {
247666d1545Sxtraeme DPRINTF(("%s: copyin_ioctl error=%d\n",
248666d1545Sxtraeme __func__, error));
249bf4558f8Sxtraeme break;
250666d1545Sxtraeme }
251bf4558f8Sxtraeme
2526c4da82bSxtraeme iter = prop_dictionary_iterator(udict);
2536c4da82bSxtraeme if (!iter) {
254bf4558f8Sxtraeme prop_object_release(udict);
2556c4da82bSxtraeme return ENOMEM;
25659e0238fSexplorer }
257e67f5e66Sthorpej
2586c4da82bSxtraeme /*
2596c4da82bSxtraeme * Iterate over the userland dictionary and process
2606c4da82bSxtraeme * the list of devices.
2616c4da82bSxtraeme */
2626c4da82bSxtraeme while ((obj = prop_object_iterator_next(iter))) {
2636c4da82bSxtraeme array_u = prop_dictionary_get_keysym(udict, obj);
2646c4da82bSxtraeme if (prop_object_type(array_u) != PROP_TYPE_ARRAY) {
2656c4da82bSxtraeme prop_object_iterator_release(iter);
2666c4da82bSxtraeme prop_object_release(udict);
2676c4da82bSxtraeme return EINVAL;
2686c4da82bSxtraeme }
269bf4558f8Sxtraeme
270a2b798fdSthorpej devname = prop_dictionary_keysym_value(obj);
2716c4da82bSxtraeme DPRINTF(("%s: processing the '%s' array requests\n",
2726c4da82bSxtraeme __func__, devname));
2736c4da82bSxtraeme
2746c4da82bSxtraeme /*
2756c4da82bSxtraeme * find the correct sme device.
2766c4da82bSxtraeme */
277bf4558f8Sxtraeme sme = sysmon_envsys_find(devname);
2786c4da82bSxtraeme if (!sme) {
279bf4558f8Sxtraeme DPRINTF(("%s: NULL sme\n", __func__));
2806c4da82bSxtraeme prop_object_iterator_release(iter);
281bf4558f8Sxtraeme prop_object_release(udict);
2826c4da82bSxtraeme return EINVAL;
283e67f5e66Sthorpej }
284bf4558f8Sxtraeme
285bf4558f8Sxtraeme /*
2866c4da82bSxtraeme * Find the correct array object with the string
2876c4da82bSxtraeme * supplied by the userland dictionary.
288bf4558f8Sxtraeme */
2896c4da82bSxtraeme array_k = prop_dictionary_get(sme_propd, devname);
2906c4da82bSxtraeme if (prop_object_type(array_k) != PROP_TYPE_ARRAY) {
2916c4da82bSxtraeme DPRINTF(("%s: array device failed\n",
2926c4da82bSxtraeme __func__));
2935ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
2946c4da82bSxtraeme prop_object_iterator_release(iter);
295bf4558f8Sxtraeme prop_object_release(udict);
2966c4da82bSxtraeme return EINVAL;
2976c4da82bSxtraeme }
2986c4da82bSxtraeme
2996c4da82bSxtraeme iter2 = prop_array_iterator(array_u);
3006c4da82bSxtraeme if (!iter2) {
3015ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
3026c4da82bSxtraeme prop_object_iterator_release(iter);
3036c4da82bSxtraeme prop_object_release(udict);
3046c4da82bSxtraeme return ENOMEM;
3056c4da82bSxtraeme }
3066c4da82bSxtraeme
3076c4da82bSxtraeme /*
3086c4da82bSxtraeme * Iterate over the array of dictionaries to
30931962fc6Sxtraeme * process the list of sensors and properties.
3106c4da82bSxtraeme */
3116c4da82bSxtraeme while ((obj2 = prop_object_iterator_next(iter2))) {
31231962fc6Sxtraeme /*
31331962fc6Sxtraeme * do the real work now.
31431962fc6Sxtraeme */
3156c4da82bSxtraeme error = sme_userset_dictionary(sme,
3166c4da82bSxtraeme obj2,
3176c4da82bSxtraeme array_k);
3186c4da82bSxtraeme if (error) {
3195ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
3206c4da82bSxtraeme prop_object_iterator_release(iter2);
3216c4da82bSxtraeme prop_object_iterator_release(iter);
3226c4da82bSxtraeme prop_object_release(udict);
32331962fc6Sxtraeme return error;
3246c4da82bSxtraeme }
3256c4da82bSxtraeme }
3266c4da82bSxtraeme
3275ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
3286c4da82bSxtraeme prop_object_iterator_release(iter2);
3296c4da82bSxtraeme }
3306c4da82bSxtraeme
3316c4da82bSxtraeme prop_object_iterator_release(iter);
3326c4da82bSxtraeme prop_object_release(udict);
3336c4da82bSxtraeme break;
3346c4da82bSxtraeme }
33531962fc6Sxtraeme /*
33631962fc6Sxtraeme * To remove all properties from all devices registered.
33731962fc6Sxtraeme */
3386c4da82bSxtraeme case ENVSYS_REMOVEPROPS:
3396c4da82bSxtraeme {
3406c4da82bSxtraeme const struct plistref *plist = (const struct plistref *)data;
3416c4da82bSxtraeme prop_dictionary_t udict;
3426c4da82bSxtraeme prop_object_t obj;
3436c4da82bSxtraeme
3446c4da82bSxtraeme if ((flag & FWRITE) == 0)
3456c4da82bSxtraeme return EPERM;
3466c4da82bSxtraeme
3476c4da82bSxtraeme error = prop_dictionary_copyin_ioctl(plist, cmd, &udict);
3486c4da82bSxtraeme if (error) {
3496c4da82bSxtraeme DPRINTF(("%s: copyin_ioctl error=%d\n",
3506c4da82bSxtraeme __func__, error));
35159e0238fSexplorer break;
35259e0238fSexplorer }
353bf4558f8Sxtraeme
3546c4da82bSxtraeme obj = prop_dictionary_get(udict, "envsys-remove-props");
3556c4da82bSxtraeme if (!obj || !prop_bool_true(obj)) {
3566c4da82bSxtraeme DPRINTF(("%s: invalid 'envsys-remove-props'\n",
3576c4da82bSxtraeme __func__));
3586c4da82bSxtraeme return EINVAL;
3596c4da82bSxtraeme }
3606c4da82bSxtraeme
36131962fc6Sxtraeme prop_object_release(udict);
3626c4da82bSxtraeme sme_remove_userprops();
3636c4da82bSxtraeme
364e67f5e66Sthorpej break;
365e67f5e66Sthorpej }
366bf4558f8Sxtraeme /*
36731962fc6Sxtraeme * Compatibility ioctls with the old interface, only implemented
36831962fc6Sxtraeme * ENVSYS_GTREDATA and ENVSYS_GTREINFO; enough to make old
36931962fc6Sxtraeme * applications work.
370bf4558f8Sxtraeme */
371e67f5e66Sthorpej case ENVSYS_GTREDATA:
372e67f5e66Sthorpej {
373e67f5e66Sthorpej struct envsys_tre_data *tred = (void *)data;
374bf4558f8Sxtraeme envsys_data_t *edata = NULL;
37531962fc6Sxtraeme bool found = false;
376e67f5e66Sthorpej
377e67f5e66Sthorpej tred->validflags = 0;
378e67f5e66Sthorpej
37931962fc6Sxtraeme sme = sysmon_envsys_find_40(tred->sensor);
3805ee4eba8Sxtraeme if (!sme)
38131962fc6Sxtraeme break;
38231962fc6Sxtraeme
383e67f5e66Sthorpej oidx = tred->sensor;
384e67f5e66Sthorpej tred->sensor = SME_SENSOR_IDX(sme, tred->sensor);
385bf4558f8Sxtraeme
386bf4558f8Sxtraeme DPRINTFOBJ(("%s: sensor=%d oidx=%d dev=%s nsensors=%d\n",
387bf4558f8Sxtraeme __func__, tred->sensor, oidx, sme->sme_name,
388bf4558f8Sxtraeme sme->sme_nsensors));
389bf4558f8Sxtraeme
39031962fc6Sxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
39131962fc6Sxtraeme if (edata->sensor == tred->sensor) {
39231962fc6Sxtraeme found = true;
39331962fc6Sxtraeme break;
39431962fc6Sxtraeme }
39531962fc6Sxtraeme }
39631962fc6Sxtraeme
39731962fc6Sxtraeme if (!found) {
3985ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
39931962fc6Sxtraeme error = ENODEV;
40031962fc6Sxtraeme break;
40131962fc6Sxtraeme }
402bf4558f8Sxtraeme
403bf4558f8Sxtraeme if (tred->sensor < sme->sme_nsensors) {
404063727a4Spgoyette if ((sme->sme_flags & SME_POLL_ONLY) == 0) {
4055ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
40687d1d221Spgoyette sysmon_envsys_refresh_sensor(sme, edata);
4075ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
4085ee4eba8Sxtraeme }
409bf4558f8Sxtraeme
41031962fc6Sxtraeme /*
41131962fc6Sxtraeme * copy required values to the old interface.
41231962fc6Sxtraeme */
413bf4558f8Sxtraeme tred->sensor = edata->sensor;
414bf4558f8Sxtraeme tred->cur.data_us = edata->value_cur;
415bf4558f8Sxtraeme tred->cur.data_s = edata->value_cur;
416bf4558f8Sxtraeme tred->max.data_us = edata->value_max;
417bf4558f8Sxtraeme tred->max.data_s = edata->value_max;
418bf4558f8Sxtraeme tred->min.data_us = edata->value_min;
419bf4558f8Sxtraeme tred->min.data_s = edata->value_min;
42077b2e2fcSpgoyette tred->avg.data_us = 0;
42177b2e2fcSpgoyette tred->avg.data_s = 0;
4224e10a848Sxtraeme if (edata->units == ENVSYS_BATTERY_CHARGE)
4234e10a848Sxtraeme tred->units = ENVSYS_INDICATOR;
4244e10a848Sxtraeme else
425bf4558f8Sxtraeme tred->units = edata->units;
426bf4558f8Sxtraeme
42768bb919dSxtraeme tred->validflags |= ENVSYS_FVALID;
42868bb919dSxtraeme tred->validflags |= ENVSYS_FCURVALID;
42968bb919dSxtraeme
43068bb919dSxtraeme if (edata->flags & ENVSYS_FPERCENT) {
43168bb919dSxtraeme tred->validflags |= ENVSYS_FMAXVALID;
43268bb919dSxtraeme tred->validflags |= ENVSYS_FFRACVALID;
433bf4558f8Sxtraeme }
434bf4558f8Sxtraeme
43531962fc6Sxtraeme if (edata->state == ENVSYS_SINVALID) {
43668bb919dSxtraeme tred->validflags &= ~ENVSYS_FCURVALID;
43768bb919dSxtraeme tred->cur.data_us = tred->cur.data_s = 0;
43868bb919dSxtraeme }
439bf4558f8Sxtraeme
440bf4558f8Sxtraeme DPRINTFOBJ(("%s: sensor=%s tred->cur.data_s=%d\n",
441bf4558f8Sxtraeme __func__, edata->desc, tred->cur.data_s));
442bf4558f8Sxtraeme DPRINTFOBJ(("%s: tred->validflags=%d tred->units=%d"
443bf4558f8Sxtraeme " tred->sensor=%d\n", __func__, tred->validflags,
444bf4558f8Sxtraeme tred->units, tred->sensor));
44557b53bc9Sjdolecek }
446e67f5e66Sthorpej tred->sensor = oidx;
4475ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
448bf4558f8Sxtraeme
449e67f5e66Sthorpej break;
450e67f5e66Sthorpej }
451e67f5e66Sthorpej case ENVSYS_GTREINFO:
452e67f5e66Sthorpej {
453e67f5e66Sthorpej struct envsys_basic_info *binfo = (void *)data;
454bf4558f8Sxtraeme envsys_data_t *edata = NULL;
45531962fc6Sxtraeme bool found = false;
456e67f5e66Sthorpej
457e67f5e66Sthorpej binfo->validflags = 0;
458e67f5e66Sthorpej
45931962fc6Sxtraeme sme = sysmon_envsys_find_40(binfo->sensor);
4605ee4eba8Sxtraeme if (!sme)
46131962fc6Sxtraeme break;
46231962fc6Sxtraeme
463e67f5e66Sthorpej oidx = binfo->sensor;
464e67f5e66Sthorpej binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
465bf4558f8Sxtraeme
46631962fc6Sxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
46731962fc6Sxtraeme if (edata->sensor == binfo->sensor) {
46831962fc6Sxtraeme found = true;
46931962fc6Sxtraeme break;
47031962fc6Sxtraeme }
47131962fc6Sxtraeme }
47231962fc6Sxtraeme
47331962fc6Sxtraeme if (!found) {
4745ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
47531962fc6Sxtraeme error = ENODEV;
47631962fc6Sxtraeme break;
47731962fc6Sxtraeme }
478bf4558f8Sxtraeme
47968bb919dSxtraeme binfo->validflags |= ENVSYS_FVALID;
480bf4558f8Sxtraeme
481bf4558f8Sxtraeme if (binfo->sensor < sme->sme_nsensors) {
4824e10a848Sxtraeme if (edata->units == ENVSYS_BATTERY_CHARGE)
4834e10a848Sxtraeme binfo->units = ENVSYS_INDICATOR;
4844e10a848Sxtraeme else
485bf4558f8Sxtraeme binfo->units = edata->units;
486812fa1c5Splunky
487812fa1c5Splunky /*
488812fa1c5Splunky * previously, the ACPI sensor names included the
489812fa1c5Splunky * device name. Include that in compatibility code.
490812fa1c5Splunky */
491812fa1c5Splunky if (strncmp(sme->sme_name, "acpi", 4) == 0)
492812fa1c5Splunky (void)snprintf(binfo->desc, sizeof(binfo->desc),
493812fa1c5Splunky "%s %s", sme->sme_name, edata->desc);
494812fa1c5Splunky else
495bf4558f8Sxtraeme (void)strlcpy(binfo->desc, edata->desc,
496bf4558f8Sxtraeme sizeof(binfo->desc));
497bf4558f8Sxtraeme }
498bf4558f8Sxtraeme
499bf4558f8Sxtraeme DPRINTFOBJ(("%s: binfo->units=%d binfo->validflags=%d\n",
500bf4558f8Sxtraeme __func__, binfo->units, binfo->validflags));
501bf4558f8Sxtraeme DPRINTFOBJ(("%s: binfo->desc=%s binfo->sensor=%d\n",
502bf4558f8Sxtraeme __func__, binfo->desc, binfo->sensor));
503bf4558f8Sxtraeme
504e67f5e66Sthorpej binfo->sensor = oidx;
5055ee4eba8Sxtraeme sysmon_envsys_release(sme, false);
506bf4558f8Sxtraeme
507bf4558f8Sxtraeme break;
508bf4558f8Sxtraeme }
509bf4558f8Sxtraeme default:
510bf4558f8Sxtraeme error = ENOTTY;
511e67f5e66Sthorpej break;
512e67f5e66Sthorpej }
513e67f5e66Sthorpej
514bf4558f8Sxtraeme return error;
515e67f5e66Sthorpej }
516e67f5e66Sthorpej
517e67f5e66Sthorpej /*
51831962fc6Sxtraeme * sysmon_envsys_create:
51931962fc6Sxtraeme *
52031962fc6Sxtraeme * + Allocates a new sysmon_envsys object and initializes the
52131962fc6Sxtraeme * stuff for sensors and events.
52231962fc6Sxtraeme */
52331962fc6Sxtraeme struct sysmon_envsys *
sysmon_envsys_create(void)52431962fc6Sxtraeme sysmon_envsys_create(void)
52531962fc6Sxtraeme {
52631962fc6Sxtraeme struct sysmon_envsys *sme;
52731962fc6Sxtraeme
528cf974319Spgoyette CTASSERT(SME_CALLOUT_INVALID == 0);
529cf974319Spgoyette
53031962fc6Sxtraeme sme = kmem_zalloc(sizeof(*sme), KM_SLEEP);
53131962fc6Sxtraeme TAILQ_INIT(&sme->sme_sensors_list);
53231962fc6Sxtraeme LIST_INIT(&sme->sme_events_list);
5335ee4eba8Sxtraeme mutex_init(&sme->sme_mtx, MUTEX_DEFAULT, IPL_NONE);
534d7a982b2Sriastradh mutex_init(&sme->sme_work_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
5355ee4eba8Sxtraeme cv_init(&sme->sme_condvar, "sme_wait");
53631962fc6Sxtraeme
53731962fc6Sxtraeme return sme;
53831962fc6Sxtraeme }
53931962fc6Sxtraeme
54031962fc6Sxtraeme /*
54131962fc6Sxtraeme * sysmon_envsys_destroy:
54231962fc6Sxtraeme *
543b5abdb42Sxtraeme * + Removes all sensors from the tail queue, destroys the callout
544b5abdb42Sxtraeme * and frees the sysmon_envsys object.
54531962fc6Sxtraeme */
54631962fc6Sxtraeme void
sysmon_envsys_destroy(struct sysmon_envsys * sme)54731962fc6Sxtraeme sysmon_envsys_destroy(struct sysmon_envsys *sme)
54831962fc6Sxtraeme {
54931962fc6Sxtraeme envsys_data_t *edata;
55031962fc6Sxtraeme
55131962fc6Sxtraeme KASSERT(sme != NULL);
55231962fc6Sxtraeme
55331962fc6Sxtraeme while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
55431962fc6Sxtraeme edata = TAILQ_FIRST(&sme->sme_sensors_list);
55531962fc6Sxtraeme TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
55631962fc6Sxtraeme }
5575ee4eba8Sxtraeme mutex_destroy(&sme->sme_mtx);
55809695533Shannken mutex_destroy(&sme->sme_work_mtx);
5595ee4eba8Sxtraeme cv_destroy(&sme->sme_condvar);
56031962fc6Sxtraeme kmem_free(sme, sizeof(*sme));
56131962fc6Sxtraeme }
56231962fc6Sxtraeme
56331962fc6Sxtraeme /*
56431962fc6Sxtraeme * sysmon_envsys_sensor_attach:
56531962fc6Sxtraeme *
566941f09b7Spgoyette * + Attaches a sensor into a sysmon_envsys device checking that units
56731962fc6Sxtraeme * is set to a valid type and description is unique and not empty.
56831962fc6Sxtraeme */
56931962fc6Sxtraeme int
sysmon_envsys_sensor_attach(struct sysmon_envsys * sme,envsys_data_t * edata)57031962fc6Sxtraeme sysmon_envsys_sensor_attach(struct sysmon_envsys *sme, envsys_data_t *edata)
57131962fc6Sxtraeme {
572e76f489bSpgoyette const struct sme_descr_entry *sdt_units;
57331962fc6Sxtraeme envsys_data_t *oedata;
57431962fc6Sxtraeme
57531962fc6Sxtraeme KASSERT(sme != NULL || edata != NULL);
57631962fc6Sxtraeme
57731962fc6Sxtraeme /*
57831962fc6Sxtraeme * Find the correct units for this sensor.
57931962fc6Sxtraeme */
580e76f489bSpgoyette sdt_units = sme_find_table_entry(SME_DESC_UNITS, edata->units);
581711fe446Sthorpej if (sdt_units == NULL || sdt_units->type == -1)
58231962fc6Sxtraeme return EINVAL;
58331962fc6Sxtraeme
58431962fc6Sxtraeme /*
58531962fc6Sxtraeme * Check that description is not empty or duplicate.
58631962fc6Sxtraeme */
58731962fc6Sxtraeme if (strlen(edata->desc) == 0)
58831962fc6Sxtraeme return EINVAL;
58931962fc6Sxtraeme
5905ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
5915ee4eba8Sxtraeme sysmon_envsys_acquire(sme, true);
59231962fc6Sxtraeme TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
59331962fc6Sxtraeme if (strcmp(oedata->desc, edata->desc) == 0) {
5945ee4eba8Sxtraeme sysmon_envsys_release(sme, true);
5955ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
59631962fc6Sxtraeme return EEXIST;
59731962fc6Sxtraeme }
59831962fc6Sxtraeme }
59931962fc6Sxtraeme /*
60031962fc6Sxtraeme * Ok, the sensor has been added into the device queue.
60131962fc6Sxtraeme */
60231962fc6Sxtraeme TAILQ_INSERT_TAIL(&sme->sme_sensors_list, edata, sensors_head);
60331962fc6Sxtraeme
60431962fc6Sxtraeme /*
605941f09b7Spgoyette * Give the sensor an index position.
60631962fc6Sxtraeme */
60731962fc6Sxtraeme edata->sensor = sme->sme_nsensors;
60831962fc6Sxtraeme sme->sme_nsensors++;
6095ee4eba8Sxtraeme sysmon_envsys_release(sme, true);
6105ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
61131962fc6Sxtraeme
612e17701cfSpgoyette DPRINTF(("%s: attached #%d (%s), units=%d (%s)\n",
613e17701cfSpgoyette __func__, edata->sensor, edata->desc,
614e76f489bSpgoyette sdt_units->type, sdt_units->desc));
615f7ad7038Spgoyette
61631962fc6Sxtraeme return 0;
61731962fc6Sxtraeme }
61831962fc6Sxtraeme
61931962fc6Sxtraeme /*
62031962fc6Sxtraeme * sysmon_envsys_sensor_detach:
62131962fc6Sxtraeme *
62231962fc6Sxtraeme * + Detachs a sensor from a sysmon_envsys device and decrements the
62331962fc6Sxtraeme * sensors count on success.
62431962fc6Sxtraeme */
62531962fc6Sxtraeme int
sysmon_envsys_sensor_detach(struct sysmon_envsys * sme,envsys_data_t * edata)62631962fc6Sxtraeme sysmon_envsys_sensor_detach(struct sysmon_envsys *sme, envsys_data_t *edata)
62731962fc6Sxtraeme {
62831962fc6Sxtraeme envsys_data_t *oedata;
62931962fc6Sxtraeme bool found = false;
63087318503Sozaki-r bool destroy = false;
63131962fc6Sxtraeme
63231962fc6Sxtraeme KASSERT(sme != NULL || edata != NULL);
63331962fc6Sxtraeme
63431962fc6Sxtraeme /*
63531962fc6Sxtraeme * Check the sensor is already on the list.
63631962fc6Sxtraeme */
6375ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
6385ee4eba8Sxtraeme sysmon_envsys_acquire(sme, true);
63931962fc6Sxtraeme TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
64031962fc6Sxtraeme if (oedata->sensor == edata->sensor) {
64131962fc6Sxtraeme found = true;
64231962fc6Sxtraeme break;
64331962fc6Sxtraeme }
64431962fc6Sxtraeme }
64531962fc6Sxtraeme
64631962fc6Sxtraeme if (!found) {
6475ee4eba8Sxtraeme sysmon_envsys_release(sme, true);
6485ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
64931962fc6Sxtraeme return EINVAL;
65031962fc6Sxtraeme }
65131962fc6Sxtraeme
65231962fc6Sxtraeme /*
65387d1d221Spgoyette * remove it, unhook from rnd(4), and decrement the sensors count.
65431962fc6Sxtraeme */
65501bfdbc2Smsaitoh if (oedata->flags & ENVSYS_FHAS_ENTROPY)
65601bfdbc2Smsaitoh rnd_detach_source(&oedata->rnd_src);
6570bc91edaSpgoyette sme_event_unregister_sensor(sme, edata);
658d7a982b2Sriastradh mutex_enter(&sme->sme_work_mtx);
65987318503Sozaki-r if (LIST_EMPTY(&sme->sme_events_list)) {
660cf974319Spgoyette if (sme->sme_callout_state == SME_CALLOUT_READY)
66187318503Sozaki-r sme_events_halt_callout(sme);
66287318503Sozaki-r destroy = true;
66387318503Sozaki-r }
664d7a982b2Sriastradh mutex_exit(&sme->sme_work_mtx);
66531962fc6Sxtraeme TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
66631962fc6Sxtraeme sme->sme_nsensors--;
6675ee4eba8Sxtraeme sysmon_envsys_release(sme, true);
6685ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
66931962fc6Sxtraeme
67087318503Sozaki-r if (destroy)
67187318503Sozaki-r sme_events_destroy(sme);
67287318503Sozaki-r
67331962fc6Sxtraeme return 0;
67431962fc6Sxtraeme }
67531962fc6Sxtraeme
67631962fc6Sxtraeme
67731962fc6Sxtraeme /*
678e67f5e66Sthorpej * sysmon_envsys_register:
679e67f5e66Sthorpej *
68063f1decdSxtraeme * + Register a sysmon envsys device.
68163f1decdSxtraeme * + Create array of dictionaries for a device.
682e67f5e66Sthorpej */
683e67f5e66Sthorpej int
sysmon_envsys_register(struct sysmon_envsys * sme)684e67f5e66Sthorpej sysmon_envsys_register(struct sysmon_envsys *sme)
685e67f5e66Sthorpej {
68610fa1cb8Sxtraeme struct sme_evdrv {
68710fa1cb8Sxtraeme SLIST_ENTRY(sme_evdrv) evdrv_head;
68810fa1cb8Sxtraeme sme_event_drv_t *evdrv;
68910fa1cb8Sxtraeme };
69010fa1cb8Sxtraeme SLIST_HEAD(, sme_evdrv) sme_evdrv_list;
6915ee4eba8Sxtraeme struct sme_evdrv *evdv = NULL;
692bf4558f8Sxtraeme struct sysmon_envsys *lsme;
6935ee4eba8Sxtraeme prop_array_t array = NULL;
69431962fc6Sxtraeme prop_dictionary_t dict, dict2;
695cac66f76Sxtraeme envsys_data_t *edata = NULL;
696677e91afSpgoyette sme_event_drv_t *this_evdrv;
697d5f3dc8bSpgoyette int nevent;
698a826e85aSxtraeme int error = 0;
69987d1d221Spgoyette char rnd_name[sizeof(edata->rnd_src.name)];
700cac66f76Sxtraeme
701cac66f76Sxtraeme KASSERT(sme != NULL);
702cac66f76Sxtraeme KASSERT(sme->sme_name != NULL);
703e67f5e66Sthorpej
704eb659e13Spgoyette (void)RUN_ONCE(&once_envsys, sme_preinit);
705d3160376Schristos
706bf4558f8Sxtraeme /*
7075ee4eba8Sxtraeme * Check if requested sysmon_envsys device is valid
7085ee4eba8Sxtraeme * and does not exist already in the list.
7095ee4eba8Sxtraeme */
7105ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
7115ee4eba8Sxtraeme LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
7125ee4eba8Sxtraeme if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
7135ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
7145ee4eba8Sxtraeme return EEXIST;
7155ee4eba8Sxtraeme }
7165ee4eba8Sxtraeme }
7175ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
7185ee4eba8Sxtraeme
7195ee4eba8Sxtraeme /*
72031962fc6Sxtraeme * sanity check: if SME_DISABLE_REFRESH is not set,
72131962fc6Sxtraeme * the sme_refresh function callback must be non NULL.
722bf4558f8Sxtraeme */
72331962fc6Sxtraeme if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0)
72431962fc6Sxtraeme if (!sme->sme_refresh)
725bf4558f8Sxtraeme return EINVAL;
726e67f5e66Sthorpej
727bf4558f8Sxtraeme /*
72831962fc6Sxtraeme * If the list of sensors is empty, there's no point to continue...
729bf4558f8Sxtraeme */
73031962fc6Sxtraeme if (TAILQ_EMPTY(&sme->sme_sensors_list)) {
73131962fc6Sxtraeme DPRINTF(("%s: sensors list empty for %s\n", __func__,
73231962fc6Sxtraeme sme->sme_name));
73331962fc6Sxtraeme return ENOTSUP;
734e67f5e66Sthorpej }
735e67f5e66Sthorpej
73631962fc6Sxtraeme /*
73710fa1cb8Sxtraeme * Initialize the singly linked list for driver events.
73810fa1cb8Sxtraeme */
73910fa1cb8Sxtraeme SLIST_INIT(&sme_evdrv_list);
7409df6f421Sxtraeme
7415ee4eba8Sxtraeme array = prop_array_create();
7425ee4eba8Sxtraeme if (!array)
7435ee4eba8Sxtraeme return ENOMEM;
7445ee4eba8Sxtraeme
74531962fc6Sxtraeme /*
74631962fc6Sxtraeme * Iterate over all sensors and create a dictionary per sensor.
74731962fc6Sxtraeme * We must respect the order in which the sensors were added.
74831962fc6Sxtraeme */
7495b4182eeSdyoung TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
750e83dd230Sxtraeme dict = prop_dictionary_create();
7516c4da82bSxtraeme if (!dict) {
752e83dd230Sxtraeme error = ENOMEM;
753e83dd230Sxtraeme goto out2;
754e83dd230Sxtraeme }
755e83dd230Sxtraeme
756cac66f76Sxtraeme /*
757cac66f76Sxtraeme * Create all objects in sensor's dictionary.
758cac66f76Sxtraeme */
759677e91afSpgoyette this_evdrv = sme_add_sensor_dictionary(sme, array,
7605ee4eba8Sxtraeme dict, edata);
761677e91afSpgoyette if (this_evdrv) {
762677e91afSpgoyette evdv = kmem_zalloc(sizeof(*evdv), KM_SLEEP);
763677e91afSpgoyette evdv->evdrv = this_evdrv;
7645ee4eba8Sxtraeme SLIST_INSERT_HEAD(&sme_evdrv_list, evdv, evdrv_head);
765cac66f76Sxtraeme }
766677e91afSpgoyette }
767cac66f76Sxtraeme
768cac66f76Sxtraeme /*
769cac66f76Sxtraeme * If the array does not contain any object (sensor), there's
770cac66f76Sxtraeme * no need to attach the driver.
771cac66f76Sxtraeme */
772cac66f76Sxtraeme if (prop_array_count(array) == 0) {
773cac66f76Sxtraeme error = EINVAL;
774cac66f76Sxtraeme DPRINTF(("%s: empty array for '%s'\n", __func__,
775cac66f76Sxtraeme sme->sme_name));
776cac66f76Sxtraeme goto out;
777cac66f76Sxtraeme }
77831962fc6Sxtraeme
77931962fc6Sxtraeme /*
78031962fc6Sxtraeme * Add the dictionary for the global properties of this device.
78131962fc6Sxtraeme */
78231962fc6Sxtraeme dict2 = prop_dictionary_create();
78331962fc6Sxtraeme if (!dict2) {
78431962fc6Sxtraeme error = ENOMEM;
78531962fc6Sxtraeme goto out;
78631962fc6Sxtraeme }
78731962fc6Sxtraeme
78831962fc6Sxtraeme error = sme_add_property_dictionary(sme, array, dict2);
78931962fc6Sxtraeme if (error) {
79031962fc6Sxtraeme prop_object_release(dict2);
79131962fc6Sxtraeme goto out;
79231962fc6Sxtraeme }
79331962fc6Sxtraeme
794cac66f76Sxtraeme /*
795cac66f76Sxtraeme * Add the array into the global dictionary for the driver.
796cac66f76Sxtraeme *
797cac66f76Sxtraeme * <dict>
798cac66f76Sxtraeme * <key>foo0</key>
799cac66f76Sxtraeme * <array>
800cac66f76Sxtraeme * ...
801cac66f76Sxtraeme */
8025ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
803cac66f76Sxtraeme if (!prop_dictionary_set(sme_propd, sme->sme_name, array)) {
804e83dd230Sxtraeme error = EINVAL;
805a57c1876Spgoyette mutex_exit(&sme_global_mtx);
806cac66f76Sxtraeme DPRINTF(("%s: prop_dictionary_set for '%s'\n", __func__,
807cac66f76Sxtraeme sme->sme_name));
808cac66f76Sxtraeme goto out;
809cac66f76Sxtraeme }
8105ee4eba8Sxtraeme
811cac66f76Sxtraeme /*
8129df6f421Sxtraeme * Add the device into the list.
813cac66f76Sxtraeme */
814e67f5e66Sthorpej LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list);
81510fa1cb8Sxtraeme sme->sme_fsensor = sysmon_envsys_next_sensor_index;
81610fa1cb8Sxtraeme sysmon_envsys_next_sensor_index += sme->sme_nsensors;
8175ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
818a8805287Sxtraeme
8195ee4eba8Sxtraeme out:
82031962fc6Sxtraeme /*
821f8d161b1Spgoyette * No errors? Make an initial data refresh if was requested,
822f8d161b1Spgoyette * then register the events that were set in the driver. Do
823f8d161b1Spgoyette * the refresh first in case it is needed to establish the
824f8d161b1Spgoyette * limits or max_value needed by some events.
82531962fc6Sxtraeme */
826a8805287Sxtraeme if (error == 0) {
827d5f3dc8bSpgoyette nevent = 0;
828f8d161b1Spgoyette
82987d1d221Spgoyette /*
83087d1d221Spgoyette * Hook the sensor into rnd(4) entropy pool if requested
83187d1d221Spgoyette */
83287d1d221Spgoyette TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
83387d1d221Spgoyette if (edata->flags & ENVSYS_FHAS_ENTROPY) {
834ea6af427Stls uint32_t rnd_type, rnd_flag = 0;
835b9514938Smsaitoh size_t n;
836b9514938Smsaitoh int tail = 1;
837b9514938Smsaitoh
83887d1d221Spgoyette snprintf(rnd_name, sizeof(rnd_name), "%s-%s",
83987d1d221Spgoyette sme->sme_name, edata->desc);
840b9514938Smsaitoh n = strlen(rnd_name);
841b9514938Smsaitoh /*
842b9514938Smsaitoh * 1) Remove trailing white space(s).
843b9514938Smsaitoh * 2) If space exist, replace it with '-'
844b9514938Smsaitoh */
845b9514938Smsaitoh while (--n) {
846b9514938Smsaitoh if (rnd_name[n] == ' ') {
847b9514938Smsaitoh if (tail != 0)
848b9514938Smsaitoh rnd_name[n] = '\0';
849b9514938Smsaitoh else
850b9514938Smsaitoh rnd_name[n] = '-';
851b9514938Smsaitoh } else
852b9514938Smsaitoh tail = 0;
853b9514938Smsaitoh }
854ea6af427Stls rnd_flag |= RND_FLAG_COLLECT_TIME;
855ea6af427Stls rnd_flag |= RND_FLAG_ESTIMATE_TIME;
856ea6af427Stls
857ea6af427Stls switch (edata->units) {
858ea6af427Stls case ENVSYS_STEMP:
859ea6af427Stls case ENVSYS_SFANRPM:
860ea6af427Stls case ENVSYS_INTEGER:
861ea6af427Stls rnd_type = RND_TYPE_ENV;
862ea6af427Stls rnd_flag |= RND_FLAG_COLLECT_VALUE;
863ea6af427Stls rnd_flag |= RND_FLAG_ESTIMATE_VALUE;
864ea6af427Stls break;
865ea6af427Stls case ENVSYS_SVOLTS_AC:
866ea6af427Stls case ENVSYS_SVOLTS_DC:
867ea6af427Stls case ENVSYS_SOHMS:
868ea6af427Stls case ENVSYS_SWATTS:
869ea6af427Stls case ENVSYS_SAMPS:
870ea6af427Stls case ENVSYS_SWATTHOUR:
871ea6af427Stls case ENVSYS_SAMPHOUR:
872ea6af427Stls rnd_type = RND_TYPE_POWER;
873ea6af427Stls rnd_flag |= RND_FLAG_COLLECT_VALUE;
874ea6af427Stls rnd_flag |= RND_FLAG_ESTIMATE_VALUE;
875ea6af427Stls break;
876ea6af427Stls default:
877ea6af427Stls rnd_type = RND_TYPE_UNKNOWN;
878ea6af427Stls break;
879ea6af427Stls }
88087d1d221Spgoyette rnd_attach_source(&edata->rnd_src, rnd_name,
881ea6af427Stls rnd_type, rnd_flag);
88287d1d221Spgoyette }
88387d1d221Spgoyette }
884b57b0d68Sriastradh
885b57b0d68Sriastradh if (sme->sme_flags & SME_INIT_REFRESH) {
886b57b0d68Sriastradh sysmon_task_queue_sched(0, sme_initial_refresh, sme);
887b57b0d68Sriastradh DPRINTF(("%s: scheduled initial refresh for '%s'\n",
888b57b0d68Sriastradh __func__, sme->sme_name));
889b57b0d68Sriastradh }
890b57b0d68Sriastradh SLIST_FOREACH(evdv, &sme_evdrv_list, evdrv_head) {
891b57b0d68Sriastradh sysmon_task_queue_sched(0,
892b57b0d68Sriastradh sme_event_drvadd, evdv->evdrv);
893b57b0d68Sriastradh nevent++;
894b57b0d68Sriastradh }
895d5f3dc8bSpgoyette DPRINTF(("%s: driver '%s' registered (nsens=%d nevent=%d)\n",
896d5f3dc8bSpgoyette __func__, sme->sme_name, sme->sme_nsensors, nevent));
897a8805287Sxtraeme }
8986f2d66f3Sxtraeme
899cac66f76Sxtraeme out2:
90010fa1cb8Sxtraeme while (!SLIST_EMPTY(&sme_evdrv_list)) {
9015ee4eba8Sxtraeme evdv = SLIST_FIRST(&sme_evdrv_list);
90210fa1cb8Sxtraeme SLIST_REMOVE_HEAD(&sme_evdrv_list, evdrv_head);
9035ee4eba8Sxtraeme kmem_free(evdv, sizeof(*evdv));
90410fa1cb8Sxtraeme }
9056c4da82bSxtraeme if (!error)
9066f2d66f3Sxtraeme return 0;
9076f2d66f3Sxtraeme
90831962fc6Sxtraeme /*
90931962fc6Sxtraeme * Ugh... something wasn't right; unregister all events and sensors
91031962fc6Sxtraeme * previously assigned and destroy the array with all its objects.
91131962fc6Sxtraeme */
9126f2d66f3Sxtraeme DPRINTF(("%s: failed to register '%s' (%d)\n", __func__,
9136f2d66f3Sxtraeme sme->sme_name, error));
9145ee4eba8Sxtraeme
91531962fc6Sxtraeme sme_event_unregister_all(sme);
91631962fc6Sxtraeme while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
91731962fc6Sxtraeme edata = TAILQ_FIRST(&sme->sme_sensors_list);
9185ee4eba8Sxtraeme TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
91983b57478Sxtraeme }
920e83dd230Sxtraeme sysmon_envsys_destroy_plist(array);
921bf4558f8Sxtraeme return error;
922e67f5e66Sthorpej }
923e67f5e66Sthorpej
924e67f5e66Sthorpej /*
925e83dd230Sxtraeme * sysmon_envsys_destroy_plist:
926e83dd230Sxtraeme *
927e83dd230Sxtraeme * + Remove all objects from the array of dictionaries that is
928e83dd230Sxtraeme * created in a sysmon envsys device.
929e83dd230Sxtraeme */
930e83dd230Sxtraeme static void
sysmon_envsys_destroy_plist(prop_array_t array)931e83dd230Sxtraeme sysmon_envsys_destroy_plist(prop_array_t array)
932e83dd230Sxtraeme {
933e83dd230Sxtraeme prop_object_iterator_t iter, iter2;
934aeb9b8e3Sxtraeme prop_dictionary_t dict;
935e83dd230Sxtraeme prop_object_t obj;
936e83dd230Sxtraeme
937e83dd230Sxtraeme KASSERT(array != NULL);
9385ee4eba8Sxtraeme KASSERT(prop_object_type(array) == PROP_TYPE_ARRAY);
939e83dd230Sxtraeme
94025fa55f1Sxtraeme DPRINTFOBJ(("%s: objects in array=%d\n", __func__,
941aeb9b8e3Sxtraeme prop_array_count(array)));
942aeb9b8e3Sxtraeme
943e83dd230Sxtraeme iter = prop_array_iterator(array);
9446c4da82bSxtraeme if (!iter)
945e83dd230Sxtraeme return;
946e83dd230Sxtraeme
9476c4da82bSxtraeme while ((dict = prop_object_iterator_next(iter))) {
948aeb9b8e3Sxtraeme KASSERT(prop_object_type(dict) == PROP_TYPE_DICTIONARY);
949e83dd230Sxtraeme iter2 = prop_dictionary_iterator(dict);
9506c4da82bSxtraeme if (!iter2)
951aeb9b8e3Sxtraeme goto out;
95225fa55f1Sxtraeme DPRINTFOBJ(("%s: iterating over dictionary\n", __func__));
953aeb9b8e3Sxtraeme while ((obj = prop_object_iterator_next(iter2)) != NULL) {
95425fa55f1Sxtraeme DPRINTFOBJ(("%s: obj=%s\n", __func__,
955a2b798fdSthorpej prop_dictionary_keysym_value(obj)));
956aeb9b8e3Sxtraeme prop_dictionary_remove(dict,
957a2b798fdSthorpej prop_dictionary_keysym_value(obj));
958aeb9b8e3Sxtraeme prop_object_iterator_reset(iter2);
959e83dd230Sxtraeme }
960aeb9b8e3Sxtraeme prop_object_iterator_release(iter2);
96125fa55f1Sxtraeme DPRINTFOBJ(("%s: objects in dictionary:%d\n",
962aeb9b8e3Sxtraeme __func__, prop_dictionary_count(dict)));
963e83dd230Sxtraeme prop_object_release(dict);
964e83dd230Sxtraeme }
965e83dd230Sxtraeme
966aeb9b8e3Sxtraeme out:
967e83dd230Sxtraeme prop_object_iterator_release(iter);
968aeb9b8e3Sxtraeme prop_object_release(array);
969e83dd230Sxtraeme }
970e83dd230Sxtraeme
971e83dd230Sxtraeme /*
972e67f5e66Sthorpej * sysmon_envsys_unregister:
973e67f5e66Sthorpej *
97463f1decdSxtraeme * + Unregister a sysmon envsys device.
975e67f5e66Sthorpej */
976e67f5e66Sthorpej void
sysmon_envsys_unregister(struct sysmon_envsys * sme)977e67f5e66Sthorpej sysmon_envsys_unregister(struct sysmon_envsys *sme)
978e67f5e66Sthorpej {
979e83dd230Sxtraeme prop_array_t array;
980cae66ef7Spgoyette struct sysmon_envsys *osme;
98101bfdbc2Smsaitoh envsys_data_t *edata;
9823fbf42acSxtraeme
9833fbf42acSxtraeme KASSERT(sme != NULL);
984e67f5e66Sthorpej
9859b54edd9Sxtraeme /*
986cae66ef7Spgoyette * Decrement global sensors counter and the first_sensor index
987cae66ef7Spgoyette * for remaining devices in the list (only used for compatibility
988cae66ef7Spgoyette * with previous API), and remove the device from the list.
9895ee4eba8Sxtraeme */
9905ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
9915ee4eba8Sxtraeme sysmon_envsys_next_sensor_index -= sme->sme_nsensors;
992cae66ef7Spgoyette LIST_FOREACH(osme, &sysmon_envsys_list, sme_list) {
993cae66ef7Spgoyette if (osme->sme_fsensor >= sme->sme_fsensor)
994cae66ef7Spgoyette osme->sme_fsensor -= sme->sme_nsensors;
995cae66ef7Spgoyette }
99610fa1cb8Sxtraeme LIST_REMOVE(sme, sme_list);
9975ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
9985ee4eba8Sxtraeme
999ea659a63Sbad while ((edata = TAILQ_FIRST(&sme->sme_sensors_list)) != NULL) {
100001bfdbc2Smsaitoh sysmon_envsys_sensor_detach(sme, edata);
100101bfdbc2Smsaitoh }
100201bfdbc2Smsaitoh
1003cac66f76Sxtraeme /*
100487318503Sozaki-r * Unregister all events associated with device.
100587318503Sozaki-r */
100687318503Sozaki-r sme_event_unregister_all(sme);
100787318503Sozaki-r
100887318503Sozaki-r /*
1009e83dd230Sxtraeme * Remove the device (and all its objects) from the global dictionary.
1010cac66f76Sxtraeme */
1011e83dd230Sxtraeme array = prop_dictionary_get(sme_propd, sme->sme_name);
1012aeb9b8e3Sxtraeme if (array && prop_object_type(array) == PROP_TYPE_ARRAY) {
10135ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
1014cac66f76Sxtraeme prop_dictionary_remove(sme_propd, sme->sme_name);
10155ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
1016aeb9b8e3Sxtraeme sysmon_envsys_destroy_plist(array);
1017e67f5e66Sthorpej }
101831962fc6Sxtraeme /*
101931962fc6Sxtraeme * And finally destroy the sysmon_envsys object.
102031962fc6Sxtraeme */
102131962fc6Sxtraeme sysmon_envsys_destroy(sme);
1022e83dd230Sxtraeme }
1023e67f5e66Sthorpej
1024e67f5e66Sthorpej /*
1025e67f5e66Sthorpej * sysmon_envsys_find:
1026e67f5e66Sthorpej *
10275ee4eba8Sxtraeme * + Find a sysmon envsys device and mark it as busy
10285ee4eba8Sxtraeme * once it's available.
1029e67f5e66Sthorpej */
1030e67f5e66Sthorpej struct sysmon_envsys *
sysmon_envsys_find(const char * name)1031bf4558f8Sxtraeme sysmon_envsys_find(const char *name)
1032e67f5e66Sthorpej {
1033e67f5e66Sthorpej struct sysmon_envsys *sme;
1034e67f5e66Sthorpej
10355ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
10365493a07fSdyoung LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
1037bf4558f8Sxtraeme if (strcmp(sme->sme_name, name) == 0) {
10385ee4eba8Sxtraeme sysmon_envsys_acquire(sme, false);
1039104f2a80Syamt break;
1040104f2a80Syamt }
1041e67f5e66Sthorpej }
10425ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
10435ee4eba8Sxtraeme
10445ee4eba8Sxtraeme return sme;
10455ee4eba8Sxtraeme }
10465ee4eba8Sxtraeme
10475ee4eba8Sxtraeme /*
10485ee4eba8Sxtraeme * Compatibility function with the old API.
10495ee4eba8Sxtraeme */
10505ee4eba8Sxtraeme struct sysmon_envsys *
sysmon_envsys_find_40(u_int idx)10515ee4eba8Sxtraeme sysmon_envsys_find_40(u_int idx)
10525ee4eba8Sxtraeme {
10535ee4eba8Sxtraeme struct sysmon_envsys *sme;
10545ee4eba8Sxtraeme
10555ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
10565ee4eba8Sxtraeme LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
10575ee4eba8Sxtraeme if (idx >= sme->sme_fsensor &&
10585ee4eba8Sxtraeme idx < (sme->sme_fsensor + sme->sme_nsensors)) {
10595ee4eba8Sxtraeme sysmon_envsys_acquire(sme, false);
10605ee4eba8Sxtraeme break;
10615ee4eba8Sxtraeme }
10625ee4eba8Sxtraeme }
10635ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
10645ee4eba8Sxtraeme
1065104f2a80Syamt return sme;
1066e67f5e66Sthorpej }
1067e67f5e66Sthorpej
1068e67f5e66Sthorpej /*
106931962fc6Sxtraeme * sysmon_envsys_acquire:
107031962fc6Sxtraeme *
10715ee4eba8Sxtraeme * + Wait until a sysmon envsys device is available and mark
10725ee4eba8Sxtraeme * it as busy.
107331962fc6Sxtraeme */
107431962fc6Sxtraeme void
sysmon_envsys_acquire(struct sysmon_envsys * sme,bool locked)10755ee4eba8Sxtraeme sysmon_envsys_acquire(struct sysmon_envsys *sme, bool locked)
107631962fc6Sxtraeme {
10775ee4eba8Sxtraeme KASSERT(sme != NULL);
107831962fc6Sxtraeme
10795ee4eba8Sxtraeme if (locked) {
108031962fc6Sxtraeme while (sme->sme_flags & SME_FLAG_BUSY)
10815ee4eba8Sxtraeme cv_wait(&sme->sme_condvar, &sme->sme_mtx);
108231962fc6Sxtraeme sme->sme_flags |= SME_FLAG_BUSY;
10835ee4eba8Sxtraeme } else {
10845ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
10855ee4eba8Sxtraeme while (sme->sme_flags & SME_FLAG_BUSY)
10865ee4eba8Sxtraeme cv_wait(&sme->sme_condvar, &sme->sme_mtx);
10875ee4eba8Sxtraeme sme->sme_flags |= SME_FLAG_BUSY;
10885ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
10895ee4eba8Sxtraeme }
109031962fc6Sxtraeme }
109131962fc6Sxtraeme
109231962fc6Sxtraeme /*
1093e67f5e66Sthorpej * sysmon_envsys_release:
1094e67f5e66Sthorpej *
10955ee4eba8Sxtraeme * + Unmark a sysmon envsys device as busy, and notify
10965ee4eba8Sxtraeme * waiters.
1097e67f5e66Sthorpej */
1098e67f5e66Sthorpej void
sysmon_envsys_release(struct sysmon_envsys * sme,bool locked)10995ee4eba8Sxtraeme sysmon_envsys_release(struct sysmon_envsys *sme, bool locked)
1100e67f5e66Sthorpej {
11015ee4eba8Sxtraeme KASSERT(sme != NULL);
110231962fc6Sxtraeme
11035ee4eba8Sxtraeme if (locked) {
110431962fc6Sxtraeme sme->sme_flags &= ~SME_FLAG_BUSY;
11055ee4eba8Sxtraeme cv_broadcast(&sme->sme_condvar);
11065ee4eba8Sxtraeme } else {
11075ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
11085ee4eba8Sxtraeme sme->sme_flags &= ~SME_FLAG_BUSY;
11095ee4eba8Sxtraeme cv_broadcast(&sme->sme_condvar);
11105ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
1111bf4558f8Sxtraeme }
1112bf4558f8Sxtraeme }
1113bf4558f8Sxtraeme
1114bf4558f8Sxtraeme /*
1115a826e85aSxtraeme * sme_initial_refresh:
1116a826e85aSxtraeme *
1117a826e85aSxtraeme * + Do an initial refresh of the sensors in a device just after
1118a826e85aSxtraeme * interrupts are enabled in the autoconf(9) process.
1119a826e85aSxtraeme *
1120a826e85aSxtraeme */
1121a826e85aSxtraeme static void
sme_initial_refresh(void * arg)1122a826e85aSxtraeme sme_initial_refresh(void *arg)
1123a826e85aSxtraeme {
1124a826e85aSxtraeme struct sysmon_envsys *sme = arg;
1125a826e85aSxtraeme envsys_data_t *edata;
1126a826e85aSxtraeme
11275ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
11285ee4eba8Sxtraeme sysmon_envsys_acquire(sme, true);
1129a826e85aSxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head)
113087d1d221Spgoyette sysmon_envsys_refresh_sensor(sme, edata);
11315ee4eba8Sxtraeme sysmon_envsys_release(sme, true);
11325ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
1133a826e85aSxtraeme }
1134a826e85aSxtraeme
1135a826e85aSxtraeme /*
11366c4da82bSxtraeme * sme_sensor_dictionary_get:
11376c4da82bSxtraeme *
113831962fc6Sxtraeme * + Returns a dictionary of a device specified by its index
113931962fc6Sxtraeme * position.
11406c4da82bSxtraeme */
11416c4da82bSxtraeme prop_dictionary_t
sme_sensor_dictionary_get(prop_array_t array,const char * index)11426c4da82bSxtraeme sme_sensor_dictionary_get(prop_array_t array, const char *index)
11436c4da82bSxtraeme {
11446c4da82bSxtraeme prop_object_iterator_t iter;
11456c4da82bSxtraeme prop_dictionary_t dict;
11466c4da82bSxtraeme prop_object_t obj;
11476c4da82bSxtraeme
11486c4da82bSxtraeme KASSERT(array != NULL || index != NULL);
11496c4da82bSxtraeme
11506c4da82bSxtraeme iter = prop_array_iterator(array);
11516c4da82bSxtraeme if (!iter)
11526c4da82bSxtraeme return NULL;
11536c4da82bSxtraeme
11546c4da82bSxtraeme while ((dict = prop_object_iterator_next(iter))) {
11556c4da82bSxtraeme obj = prop_dictionary_get(dict, "index");
1156814a7798Sthorpej if (prop_string_equals_string(obj, index))
11576c4da82bSxtraeme break;
11586c4da82bSxtraeme }
11596c4da82bSxtraeme
11606c4da82bSxtraeme prop_object_iterator_release(iter);
11616c4da82bSxtraeme return dict;
11626c4da82bSxtraeme }
11636c4da82bSxtraeme
11646c4da82bSxtraeme /*
11656c4da82bSxtraeme * sme_remove_userprops:
11666c4da82bSxtraeme *
11676c4da82bSxtraeme * + Remove all properties from all devices that were set by
116831962fc6Sxtraeme * the ENVSYS_SETDICTIONARY ioctl.
11696c4da82bSxtraeme */
11706c4da82bSxtraeme static void
sme_remove_userprops(void)11716c4da82bSxtraeme sme_remove_userprops(void)
11726c4da82bSxtraeme {
11736c4da82bSxtraeme struct sysmon_envsys *sme;
11746c4da82bSxtraeme prop_array_t array;
11756c4da82bSxtraeme prop_dictionary_t sdict;
11766c4da82bSxtraeme envsys_data_t *edata = NULL;
11776c4da82bSxtraeme char tmp[ENVSYS_DESCLEN];
1178840097bfSpgoyette char rnd_name[sizeof(edata->rnd_src.name)];
1179d8f35b6eSpgoyette sysmon_envsys_lim_t lims;
1180e76f489bSpgoyette const struct sme_descr_entry *sdt_units;
118173ddb4f5Spgoyette uint32_t props;
1182e76f489bSpgoyette int ptype;
11836c4da82bSxtraeme
11845ee4eba8Sxtraeme mutex_enter(&sme_global_mtx);
11856c4da82bSxtraeme LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
11865ee4eba8Sxtraeme sysmon_envsys_acquire(sme, false);
11876c4da82bSxtraeme array = prop_dictionary_get(sme_propd, sme->sme_name);
11886c4da82bSxtraeme
118931962fc6Sxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
11906c4da82bSxtraeme (void)snprintf(tmp, sizeof(tmp), "sensor%d",
11916c4da82bSxtraeme edata->sensor);
11926c4da82bSxtraeme sdict = sme_sensor_dictionary_get(array, tmp);
119331962fc6Sxtraeme KASSERT(sdict != NULL);
11946c4da82bSxtraeme
11956d65ba83Spgoyette ptype = 0;
1196f7ad7038Spgoyette if (edata->upropset & PROP_BATTCAP) {
11976c4da82bSxtraeme prop_dictionary_remove(sdict,
11986c4da82bSxtraeme "critical-capacity");
1199f7ad7038Spgoyette ptype = PENVSYS_EVENT_CAPACITY;
12006d65ba83Spgoyette }
12016d65ba83Spgoyette
1202f7ad7038Spgoyette if (edata->upropset & PROP_BATTWARN) {
12036d65ba83Spgoyette prop_dictionary_remove(sdict,
12046d65ba83Spgoyette "warning-capacity");
1205f7ad7038Spgoyette ptype = PENVSYS_EVENT_CAPACITY;
12066d65ba83Spgoyette }
12078844275bSpgoyette
12088844275bSpgoyette if (edata->upropset & PROP_BATTHIGH) {
12098844275bSpgoyette prop_dictionary_remove(sdict,
12108844275bSpgoyette "high-capacity");
12118844275bSpgoyette ptype = PENVSYS_EVENT_CAPACITY;
12128844275bSpgoyette }
12138844275bSpgoyette
12148844275bSpgoyette if (edata->upropset & PROP_BATTMAX) {
12158844275bSpgoyette prop_dictionary_remove(sdict,
12168844275bSpgoyette "maximum-capacity");
12178844275bSpgoyette ptype = PENVSYS_EVENT_CAPACITY;
12188844275bSpgoyette }
1219f7ad7038Spgoyette if (edata->upropset & PROP_WARNMAX) {
1220f7ad7038Spgoyette prop_dictionary_remove(sdict, "warning-max");
1221f7ad7038Spgoyette ptype = PENVSYS_EVENT_LIMITS;
12226d65ba83Spgoyette }
12236d65ba83Spgoyette
1224f7ad7038Spgoyette if (edata->upropset & PROP_WARNMIN) {
1225f7ad7038Spgoyette prop_dictionary_remove(sdict, "warning-min");
1226f7ad7038Spgoyette ptype = PENVSYS_EVENT_LIMITS;
12276c4da82bSxtraeme }
12286c4da82bSxtraeme
1229f7ad7038Spgoyette if (edata->upropset & PROP_CRITMAX) {
1230f7ad7038Spgoyette prop_dictionary_remove(sdict, "critical-max");
1231f7ad7038Spgoyette ptype = PENVSYS_EVENT_LIMITS;
12326c4da82bSxtraeme }
12336c4da82bSxtraeme
1234f7ad7038Spgoyette if (edata->upropset & PROP_CRITMIN) {
1235f7ad7038Spgoyette prop_dictionary_remove(sdict, "critical-min");
1236f7ad7038Spgoyette ptype = PENVSYS_EVENT_LIMITS;
12376c4da82bSxtraeme }
1238f7ad7038Spgoyette if (edata->upropset & PROP_RFACT) {
12396c4da82bSxtraeme (void)sme_sensor_upint32(sdict, "rfact", 0);
12406c4da82bSxtraeme edata->rfact = 0;
12416c4da82bSxtraeme }
12426c4da82bSxtraeme
1243f7ad7038Spgoyette if (edata->upropset & PROP_DESC)
12446c4da82bSxtraeme (void)sme_sensor_upstring(sdict,
12456c4da82bSxtraeme "description", edata->desc);
12466c4da82bSxtraeme
1247d8f35b6eSpgoyette if (ptype == 0)
1248d8f35b6eSpgoyette continue;
1249d8f35b6eSpgoyette
1250d8f35b6eSpgoyette /*
1251d8f35b6eSpgoyette * If there were any limit values removed, we
1252d8f35b6eSpgoyette * need to revert to initial limits.
1253d8f35b6eSpgoyette *
1254d8f35b6eSpgoyette * First, tell the driver that we need it to
1255d8f35b6eSpgoyette * restore any h/w limits which may have been
125673ddb4f5Spgoyette * changed to stored, boot-time values.
1257d8f35b6eSpgoyette */
1258d8f35b6eSpgoyette if (sme->sme_set_limits) {
1259d8f35b6eSpgoyette DPRINTF(("%s: reset limits for %s %s\n",
1260d8f35b6eSpgoyette __func__, sme->sme_name, edata->desc));
1261d8f35b6eSpgoyette (*sme->sme_set_limits)(sme, edata, NULL, NULL);
1262d8f35b6eSpgoyette }
126373ddb4f5Spgoyette
126473ddb4f5Spgoyette /*
126573ddb4f5Spgoyette * Next, we need to retrieve those initial limits.
126673ddb4f5Spgoyette */
1267608cbb3aSnjoly props = 0;
126873ddb4f5Spgoyette edata->upropset &= ~PROP_LIMITS;
1269d8f35b6eSpgoyette if (sme->sme_get_limits) {
1270d8f35b6eSpgoyette DPRINTF(("%s: retrieve limits for %s %s\n",
1271d8f35b6eSpgoyette __func__, sme->sme_name, edata->desc));
1272d8f35b6eSpgoyette lims = edata->limits;
1273d8f35b6eSpgoyette (*sme->sme_get_limits)(sme, edata, &lims,
127473ddb4f5Spgoyette &props);
127573ddb4f5Spgoyette }
12769179849bSpgoyette
127773ddb4f5Spgoyette /*
1278cf974319Spgoyette * If the sensor is providing entropy data,
1279cf974319Spgoyette * get rid of the rndsrc; we'll provide a new
1280cf974319Spgoyette * one shortly.
1281cf974319Spgoyette */
1282cf974319Spgoyette if (edata->flags & ENVSYS_FHAS_ENTROPY)
1283cf974319Spgoyette rnd_detach_source(&edata->rnd_src);
1284cf974319Spgoyette
1285cf974319Spgoyette /*
1286cf974319Spgoyette * Remove the old limits event, if any
128773ddb4f5Spgoyette */
128873ddb4f5Spgoyette sme_event_unregister(sme, edata->desc,
128973ddb4f5Spgoyette PENVSYS_EVENT_LIMITS);
129073ddb4f5Spgoyette
129173ddb4f5Spgoyette /*
1292cf974319Spgoyette * Create and install a new event (which will
1293cf974319Spgoyette * update the dictionary) with the correct
1294cf974319Spgoyette * units.
129573ddb4f5Spgoyette */
1296e76f489bSpgoyette sdt_units = sme_find_table_entry(SME_DESC_UNITS,
1297e76f489bSpgoyette edata->units);
129873ddb4f5Spgoyette
1299840097bfSpgoyette if (props & PROP_LIMITS) {
1300840097bfSpgoyette DPRINTF(("%s: install limits for %s %s\n",
1301840097bfSpgoyette __func__, sme->sme_name, edata->desc));
1302840097bfSpgoyette
130373ddb4f5Spgoyette sme_event_register(sdict, edata, sme,
130473ddb4f5Spgoyette &lims, props, PENVSYS_EVENT_LIMITS,
1305e76f489bSpgoyette sdt_units->crittype);
1306d8f35b6eSpgoyette }
1307cf974319Spgoyette
1308cf974319Spgoyette /* Finally, if the sensor provides entropy,
1309cf974319Spgoyette * create an additional event entry and attach
1310cf974319Spgoyette * the rndsrc
1311cf974319Spgoyette */
1312840097bfSpgoyette if (edata->flags & ENVSYS_FHAS_ENTROPY) {
1313840097bfSpgoyette sme_event_register(sdict, edata, sme,
1314840097bfSpgoyette &lims, props, PENVSYS_EVENT_NULL,
1315840097bfSpgoyette sdt_units->crittype);
1316840097bfSpgoyette snprintf(rnd_name, sizeof(rnd_name), "%s-%s",
1317840097bfSpgoyette sme->sme_name, edata->desc);
1318840097bfSpgoyette rnd_attach_source(&edata->rnd_src, rnd_name,
1319ea6af427Stls RND_TYPE_ENV, RND_FLAG_COLLECT_VALUE|
1320ea6af427Stls RND_FLAG_COLLECT_TIME|
1321ea6af427Stls RND_FLAG_ESTIMATE_VALUE|
1322ea6af427Stls RND_FLAG_ESTIMATE_TIME);
1323840097bfSpgoyette }
132431962fc6Sxtraeme }
13256c4da82bSxtraeme
132631962fc6Sxtraeme /*
132731962fc6Sxtraeme * Restore default timeout value.
132831962fc6Sxtraeme */
1329d7a982b2Sriastradh mutex_enter(&sme->sme_work_mtx);
133031962fc6Sxtraeme sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
133159fe847eSpgoyette sme_schedule_callout(sme);
1332d7a982b2Sriastradh mutex_exit(&sme->sme_work_mtx);
1333d7a982b2Sriastradh
1334d7a982b2Sriastradh sysmon_envsys_release(sme, false);
13356c4da82bSxtraeme }
13365ee4eba8Sxtraeme mutex_exit(&sme_global_mtx);
13376c4da82bSxtraeme }
133831962fc6Sxtraeme
13396c4da82bSxtraeme /*
134031962fc6Sxtraeme * sme_add_property_dictionary:
13419b54edd9Sxtraeme *
134231962fc6Sxtraeme * + Add global properties into a device.
13439b54edd9Sxtraeme */
13449b54edd9Sxtraeme static int
sme_add_property_dictionary(struct sysmon_envsys * sme,prop_array_t array,prop_dictionary_t dict)134531962fc6Sxtraeme sme_add_property_dictionary(struct sysmon_envsys *sme, prop_array_t array,
134631962fc6Sxtraeme prop_dictionary_t dict)
13479b54edd9Sxtraeme {
134831962fc6Sxtraeme prop_dictionary_t pdict;
1349d7a982b2Sriastradh uint64_t timo;
1350e235f1e8Spgoyette const char *class;
135131962fc6Sxtraeme int error = 0;
13529b54edd9Sxtraeme
135331962fc6Sxtraeme pdict = prop_dictionary_create();
135431962fc6Sxtraeme if (!pdict)
135531962fc6Sxtraeme return EINVAL;
13563fbf42acSxtraeme
1357666d1545Sxtraeme /*
1358e235f1e8Spgoyette * Add the 'refresh-timeout' and 'dev-class' objects into the
1359e235f1e8Spgoyette * 'device-properties' dictionary.
136031962fc6Sxtraeme *
136131962fc6Sxtraeme * ...
136231962fc6Sxtraeme * <dict>
136331962fc6Sxtraeme * <key>device-properties</key>
136431962fc6Sxtraeme * <dict>
136531962fc6Sxtraeme * <key>refresh-timeout</key>
136631962fc6Sxtraeme * <integer>120</integer<
1367e235f1e8Spgoyette * <key>device-class</key>
1368e235f1e8Spgoyette * <string>class_name</string>
1369e235f1e8Spgoyette * </dict>
137031962fc6Sxtraeme * </dict>
137131962fc6Sxtraeme * ...
137231962fc6Sxtraeme *
1373666d1545Sxtraeme */
1374d7a982b2Sriastradh mutex_enter(&sme->sme_work_mtx);
137559fe847eSpgoyette if (sme->sme_events_timeout == 0) {
137631962fc6Sxtraeme sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
137759fe847eSpgoyette sme_schedule_callout(sme);
137859fe847eSpgoyette }
1379d7a982b2Sriastradh timo = sme->sme_events_timeout;
1380d7a982b2Sriastradh mutex_exit(&sme->sme_work_mtx);
138131962fc6Sxtraeme
1382d7a982b2Sriastradh if (!prop_dictionary_set_uint64(pdict, "refresh-timeout", timo)) {
138331962fc6Sxtraeme error = EINVAL;
138431962fc6Sxtraeme goto out;
13859b54edd9Sxtraeme }
1386e235f1e8Spgoyette if (sme->sme_class == SME_CLASS_BATTERY)
1387e235f1e8Spgoyette class = "battery";
1388e235f1e8Spgoyette else if (sme->sme_class == SME_CLASS_ACADAPTER)
1389e235f1e8Spgoyette class = "ac-adapter";
1390e235f1e8Spgoyette else
1391e235f1e8Spgoyette class = "other";
1392814a7798Sthorpej if (!prop_dictionary_set_string_nocopy(pdict, "device-class", class)) {
1393e235f1e8Spgoyette error = EINVAL;
1394e235f1e8Spgoyette goto out;
1395e235f1e8Spgoyette }
13969b54edd9Sxtraeme
139731962fc6Sxtraeme if (!prop_dictionary_set(dict, "device-properties", pdict)) {
139831962fc6Sxtraeme error = EINVAL;
139931962fc6Sxtraeme goto out;
140031962fc6Sxtraeme }
1401cac66f76Sxtraeme
140231962fc6Sxtraeme /*
140331962fc6Sxtraeme * Add the device dictionary into the sysmon envsys array.
140431962fc6Sxtraeme */
140531962fc6Sxtraeme if (!prop_array_add(array, dict))
140631962fc6Sxtraeme error = EINVAL;
14079b54edd9Sxtraeme
140831962fc6Sxtraeme out:
140931962fc6Sxtraeme prop_object_release(pdict);
141031962fc6Sxtraeme return error;
14119b54edd9Sxtraeme }
14129b54edd9Sxtraeme
14139b54edd9Sxtraeme /*
141463f1decdSxtraeme * sme_add_sensor_dictionary:
1415bf4558f8Sxtraeme *
141631962fc6Sxtraeme * + Adds the sensor objects into the dictionary and returns a pointer
141731962fc6Sxtraeme * to a sme_event_drv_t object if a monitoring flag was set
141831962fc6Sxtraeme * (or NULL otherwise).
1419bf4558f8Sxtraeme */
1420d5f3dc8bSpgoyette static sme_event_drv_t *
sme_add_sensor_dictionary(struct sysmon_envsys * sme,prop_array_t array,prop_dictionary_t dict,envsys_data_t * edata)1421cac66f76Sxtraeme sme_add_sensor_dictionary(struct sysmon_envsys *sme, prop_array_t array,
1422cac66f76Sxtraeme prop_dictionary_t dict, envsys_data_t *edata)
1423bf4558f8Sxtraeme {
142435a3b0e4Spgoyette const struct sme_descr_entry *sdt;
142535a3b0e4Spgoyette int error;
1426bf4558f8Sxtraeme sme_event_drv_t *sme_evdrv_t = NULL;
14276c4da82bSxtraeme char indexstr[ENVSYS_DESCLEN];
1428941f09b7Spgoyette bool mon_supported, allow_rfact;
1429bf4558f8Sxtraeme
143031962fc6Sxtraeme /*
14316c4da82bSxtraeme * Add the index sensor string.
14326c4da82bSxtraeme *
14336c4da82bSxtraeme * ...
143431962fc6Sxtraeme * <key>index</eyr
14356c4da82bSxtraeme * <string>sensor0</string>
14366c4da82bSxtraeme * ...
14376c4da82bSxtraeme */
14386c4da82bSxtraeme (void)snprintf(indexstr, sizeof(indexstr), "sensor%d", edata->sensor);
14396c4da82bSxtraeme if (sme_sensor_upstring(dict, "index", indexstr))
144031962fc6Sxtraeme goto bad;
14416c4da82bSxtraeme
14426c4da82bSxtraeme /*
1443bf4558f8Sxtraeme * ...
1444bf4558f8Sxtraeme * <key>description</key>
1445bf4558f8Sxtraeme * <string>blah blah</string>
1446bf4558f8Sxtraeme * ...
1447bf4558f8Sxtraeme */
1448666d1545Sxtraeme if (sme_sensor_upstring(dict, "description", edata->desc))
144931962fc6Sxtraeme goto bad;
1450bf4558f8Sxtraeme
1451bf4558f8Sxtraeme /*
14521b3709ecSxtraeme * Add the monitoring boolean object:
14531b3709ecSxtraeme *
14541b3709ecSxtraeme * ...
14551b3709ecSxtraeme * <key>monitoring-supported</key>
14561b3709ecSxtraeme * <true/>
14571b3709ecSxtraeme * ...
14581b3709ecSxtraeme *
14594e10a848Sxtraeme * always false on Battery {capacity,charge}, Drive and Indicator types.
14601b3709ecSxtraeme * They cannot be monitored.
14611b3709ecSxtraeme *
14621b3709ecSxtraeme */
14631b3709ecSxtraeme if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
14641b3709ecSxtraeme (edata->units == ENVSYS_INDICATOR) ||
14651b3709ecSxtraeme (edata->units == ENVSYS_DRIVE) ||
14664e10a848Sxtraeme (edata->units == ENVSYS_BATTERY_CAPACITY) ||
1467941f09b7Spgoyette (edata->units == ENVSYS_BATTERY_CHARGE))
1468941f09b7Spgoyette mon_supported = false;
1469941f09b7Spgoyette else
1470941f09b7Spgoyette mon_supported = true;
1471941f09b7Spgoyette if (sme_sensor_upbool(dict, "monitoring-supported", mon_supported))
147210fa1cb8Sxtraeme goto out;
14731b3709ecSxtraeme
14741b3709ecSxtraeme /*
14756c4da82bSxtraeme * Add the allow-rfact boolean object, true if
147635a3b0e4Spgoyette * ENVSYS_FCHANGERFACT is set, false otherwise.
14776c4da82bSxtraeme *
14786c4da82bSxtraeme * ...
14796c4da82bSxtraeme * <key>allow-rfact</key>
14806c4da82bSxtraeme * <true/>
14816c4da82bSxtraeme * ...
14826c4da82bSxtraeme */
14836c4da82bSxtraeme if (edata->units == ENVSYS_SVOLTS_DC ||
14846c4da82bSxtraeme edata->units == ENVSYS_SVOLTS_AC) {
1485941f09b7Spgoyette if (edata->flags & ENVSYS_FCHANGERFACT)
1486941f09b7Spgoyette allow_rfact = true;
1487941f09b7Spgoyette else
1488941f09b7Spgoyette allow_rfact = false;
1489941f09b7Spgoyette if (sme_sensor_upbool(dict, "allow-rfact", allow_rfact))
14906c4da82bSxtraeme goto out;
14916c4da82bSxtraeme }
14926c4da82bSxtraeme
149335a3b0e4Spgoyette error = sme_update_sensor_dictionary(dict, edata,
149435a3b0e4Spgoyette (edata->state == ENVSYS_SVALID));
149535a3b0e4Spgoyette if (error < 0)
149635a3b0e4Spgoyette goto bad;
149735a3b0e4Spgoyette else if (error)
149810fa1cb8Sxtraeme goto out;
1499bf4558f8Sxtraeme
1500bf4558f8Sxtraeme /*
1501bf4558f8Sxtraeme * ...
150231962fc6Sxtraeme * </dict>
1503cac66f76Sxtraeme *
1504cac66f76Sxtraeme * Add the dictionary into the array.
1505cac66f76Sxtraeme *
1506bf4558f8Sxtraeme */
150731962fc6Sxtraeme if (!prop_array_add(array, dict)) {
1508666d1545Sxtraeme DPRINTF(("%s: prop_array_add\n", __func__));
150931962fc6Sxtraeme goto bad;
1510666d1545Sxtraeme }
1511666d1545Sxtraeme
1512666d1545Sxtraeme /*
151387d1d221Spgoyette * Register new event(s) if any monitoring flag was set or if
151487d1d221Spgoyette * the sensor provides entropy for rnd(4).
1515666d1545Sxtraeme */
151687d1d221Spgoyette if (edata->flags & (ENVSYS_FMONANY | ENVSYS_FHAS_ENTROPY)) {
151710fa1cb8Sxtraeme sme_evdrv_t = kmem_zalloc(sizeof(*sme_evdrv_t), KM_SLEEP);
151831962fc6Sxtraeme sme_evdrv_t->sed_sdict = dict;
151931962fc6Sxtraeme sme_evdrv_t->sed_edata = edata;
152031962fc6Sxtraeme sme_evdrv_t->sed_sme = sme;
152135a3b0e4Spgoyette sdt = sme_find_table_entry(SME_DESC_UNITS, edata->units);
152235a3b0e4Spgoyette sme_evdrv_t->sed_powertype = sdt->crittype;
1523666d1545Sxtraeme }
1524666d1545Sxtraeme
152510fa1cb8Sxtraeme out:
152610fa1cb8Sxtraeme return sme_evdrv_t;
1527666d1545Sxtraeme
152831962fc6Sxtraeme bad:
1529636631ccSxtraeme prop_object_release(dict);
153031962fc6Sxtraeme return NULL;
1531bf4558f8Sxtraeme }
1532bf4558f8Sxtraeme
1533bf4558f8Sxtraeme /*
1534889f82ddSmartin * Find the maximum of all currently reported values.
1535631d5867Smbalmer * The provided callback decides whether a sensor is part of the
1536889f82ddSmartin * maximum calculation (by returning true) or ignored (callback
1537889f82ddSmartin * returns false). Example usage: callback selects temperature
1538889f82ddSmartin * sensors in a given thermal zone, the function calculates the
1539889f82ddSmartin * maximum currently reported temperature in this zone.
15404ddb8793Sandvar * If the parameter "refresh" is true, new values will be acquired
1541889f82ddSmartin * from the hardware, if not, the last reported value will be used.
1542889f82ddSmartin */
1543889f82ddSmartin uint32_t
sysmon_envsys_get_max_value(bool (* predicate)(const envsys_data_t *),bool refresh)1544889f82ddSmartin sysmon_envsys_get_max_value(bool (*predicate)(const envsys_data_t*),
1545889f82ddSmartin bool refresh)
1546889f82ddSmartin {
1547889f82ddSmartin struct sysmon_envsys *sme;
1548889f82ddSmartin uint32_t maxv, v;
1549889f82ddSmartin
1550889f82ddSmartin maxv = 0;
1551889f82ddSmartin mutex_enter(&sme_global_mtx);
1552889f82ddSmartin LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
1553889f82ddSmartin sysmon_envsys_acquire(sme, false);
1554889f82ddSmartin v = sme_get_max_value(sme, predicate, refresh);
1555889f82ddSmartin sysmon_envsys_release(sme, false);
1556889f82ddSmartin if (v > maxv)
1557889f82ddSmartin maxv = v;
1558889f82ddSmartin }
1559889f82ddSmartin mutex_exit(&sme_global_mtx);
1560889f82ddSmartin return maxv;
1561889f82ddSmartin }
1562889f82ddSmartin
1563889f82ddSmartin static uint32_t
sme_get_max_value(struct sysmon_envsys * sme,bool (* predicate)(const envsys_data_t *),bool refresh)1564889f82ddSmartin sme_get_max_value(struct sysmon_envsys *sme,
1565889f82ddSmartin bool (*predicate)(const envsys_data_t*),
1566889f82ddSmartin bool refresh)
1567889f82ddSmartin {
1568889f82ddSmartin envsys_data_t *edata;
1569889f82ddSmartin uint32_t maxv, v;
1570889f82ddSmartin
1571889f82ddSmartin /*
15722a2c9660Smartin * Iterate over all sensors that match the predicate
1573889f82ddSmartin */
1574889f82ddSmartin maxv = 0;
1575889f82ddSmartin TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
1576889f82ddSmartin if (!(*predicate)(edata))
1577889f82ddSmartin continue;
1578889f82ddSmartin
1579889f82ddSmartin /*
1580063727a4Spgoyette * refresh sensor data
1581889f82ddSmartin */
1582889f82ddSmartin mutex_enter(&sme->sme_mtx);
158387d1d221Spgoyette sysmon_envsys_refresh_sensor(sme, edata);
1584889f82ddSmartin mutex_exit(&sme->sme_mtx);
1585889f82ddSmartin
1586889f82ddSmartin v = edata->value_cur;
1587889f82ddSmartin if (v > maxv)
1588889f82ddSmartin maxv = v;
1589889f82ddSmartin
1590889f82ddSmartin }
1591889f82ddSmartin
1592889f82ddSmartin return maxv;
1593889f82ddSmartin }
1594889f82ddSmartin
1595889f82ddSmartin /*
1596bf4558f8Sxtraeme * sme_update_dictionary:
1597bf4558f8Sxtraeme *
1598bf4558f8Sxtraeme * + Update per-sensor dictionaries with new values if there were
1599bf4558f8Sxtraeme * changes, otherwise the object in dictionary is untouched.
1600bf4558f8Sxtraeme */
1601bf4558f8Sxtraeme int
sme_update_dictionary(struct sysmon_envsys * sme)1602bf4558f8Sxtraeme sme_update_dictionary(struct sysmon_envsys *sme)
1603bf4558f8Sxtraeme {
16045b53183eSxtraeme envsys_data_t *edata;
160531962fc6Sxtraeme prop_object_t array, dict, obj, obj2;
1606d7a982b2Sriastradh uint64_t timo;
1607e76f489bSpgoyette int error = 0;
1608bf4558f8Sxtraeme
160931962fc6Sxtraeme /*
161031962fc6Sxtraeme * Retrieve the array of dictionaries in device.
161131962fc6Sxtraeme */
1612bf4558f8Sxtraeme array = prop_dictionary_get(sme_propd, sme->sme_name);
1613d11db10fSxtraeme if (prop_object_type(array) != PROP_TYPE_ARRAY) {
1614d11db10fSxtraeme DPRINTF(("%s: not an array (%s)\n", __func__, sme->sme_name));
1615bf4558f8Sxtraeme return EINVAL;
1616d11db10fSxtraeme }
1617bf4558f8Sxtraeme
1618bf4558f8Sxtraeme /*
161931962fc6Sxtraeme * Get the last dictionary on the array, this contains the
162031962fc6Sxtraeme * 'device-properties' sub-dictionary.
162131962fc6Sxtraeme */
162231962fc6Sxtraeme obj = prop_array_get(array, prop_array_count(array) - 1);
162331962fc6Sxtraeme if (!obj || prop_object_type(obj) != PROP_TYPE_DICTIONARY) {
162431962fc6Sxtraeme DPRINTF(("%s: not a device-properties dictionary\n", __func__));
162531962fc6Sxtraeme return EINVAL;
162631962fc6Sxtraeme }
162731962fc6Sxtraeme
162831962fc6Sxtraeme obj2 = prop_dictionary_get(obj, "device-properties");
162931962fc6Sxtraeme if (!obj2)
163031962fc6Sxtraeme return EINVAL;
163131962fc6Sxtraeme
163231962fc6Sxtraeme /*
163331962fc6Sxtraeme * Update the 'refresh-timeout' property.
163431962fc6Sxtraeme */
1635d7a982b2Sriastradh mutex_enter(&sme->sme_work_mtx);
1636d7a982b2Sriastradh timo = sme->sme_events_timeout;
1637d7a982b2Sriastradh mutex_exit(&sme->sme_work_mtx);
1638d7a982b2Sriastradh if (!prop_dictionary_set_uint64(obj2, "refresh-timeout", timo))
163931962fc6Sxtraeme return EINVAL;
164031962fc6Sxtraeme
164131962fc6Sxtraeme /*
1642bf4558f8Sxtraeme * - iterate over all sensors.
1643bf4558f8Sxtraeme * - fetch new data.
1644bf4558f8Sxtraeme * - check if data in dictionary is different than new data.
1645bf4558f8Sxtraeme * - update dictionary if there were changes.
1646bf4558f8Sxtraeme */
1647a8805287Sxtraeme DPRINTF(("%s: updating '%s' with nsensors=%d\n", __func__,
1648a8805287Sxtraeme sme->sme_name, sme->sme_nsensors));
1649a8805287Sxtraeme
16505ee4eba8Sxtraeme /*
16515ee4eba8Sxtraeme * Don't bother with locking when traversing the queue,
16525ee4eba8Sxtraeme * the device is already marked as busy; if a sensor
16535ee4eba8Sxtraeme * is going to be removed or added it will have to wait.
16545ee4eba8Sxtraeme */
165531962fc6Sxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
1656bf4558f8Sxtraeme /*
1657063727a4Spgoyette * refresh sensor data via sme_envsys_refresh_sensor
1658bf4558f8Sxtraeme */
16595ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
166087d1d221Spgoyette sysmon_envsys_refresh_sensor(sme, edata);
16615ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
1662bf4558f8Sxtraeme
166331962fc6Sxtraeme /*
166431962fc6Sxtraeme * retrieve sensor's dictionary.
166531962fc6Sxtraeme */
166631962fc6Sxtraeme dict = prop_array_get(array, edata->sensor);
1667d11db10fSxtraeme if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) {
1668d11db10fSxtraeme DPRINTF(("%s: not a dictionary (%d:%s)\n",
1669d11db10fSxtraeme __func__, edata->sensor, sme->sme_name));
1670bf4558f8Sxtraeme return EINVAL;
1671d11db10fSxtraeme }
1672bf4558f8Sxtraeme
167331962fc6Sxtraeme /*
167431962fc6Sxtraeme * update sensor's state.
167531962fc6Sxtraeme */
167635a3b0e4Spgoyette error = sme_update_sensor_dictionary(dict, edata, true);
167735a3b0e4Spgoyette
167835a3b0e4Spgoyette if (error)
167935a3b0e4Spgoyette break;
168035a3b0e4Spgoyette }
168135a3b0e4Spgoyette
168235a3b0e4Spgoyette return error;
168335a3b0e4Spgoyette }
168435a3b0e4Spgoyette
168535a3b0e4Spgoyette int
sme_update_sensor_dictionary(prop_object_t dict,envsys_data_t * edata,bool value_update)168635a3b0e4Spgoyette sme_update_sensor_dictionary(prop_object_t dict, envsys_data_t *edata,
168735a3b0e4Spgoyette bool value_update)
168835a3b0e4Spgoyette {
168935a3b0e4Spgoyette const struct sme_descr_entry *sdt;
169035a3b0e4Spgoyette int error = 0;
169135a3b0e4Spgoyette
1692e76f489bSpgoyette sdt = sme_find_table_entry(SME_DESC_STATES, edata->state);
1693b2ead544Smartin if (sdt == NULL) {
1694d7a5c44eSjdc printf("sme_update_sensor_dictionary: cannot update sensor %d "
1695d7a5c44eSjdc "state %d unknown\n", edata->sensor, edata->state);
1696b2ead544Smartin return EINVAL;
1697b2ead544Smartin }
1698bf4558f8Sxtraeme
169935a3b0e4Spgoyette DPRINTFOBJ(("%s: sensor #%d type=%d (%s) flags=%d\n", __func__,
170035a3b0e4Spgoyette edata->sensor, sdt->type, sdt->desc, edata->flags));
1701bf4558f8Sxtraeme
1702e76f489bSpgoyette error = sme_sensor_upstring(dict, "state", sdt->desc);
1703bf9c6587Sxtraeme if (error)
170435a3b0e4Spgoyette return (-error);
1705bf4558f8Sxtraeme
170631962fc6Sxtraeme /*
170731962fc6Sxtraeme * update sensor's type.
170831962fc6Sxtraeme */
1709e76f489bSpgoyette sdt = sme_find_table_entry(SME_DESC_UNITS, edata->units);
17108f4a4ed9Spgoyette if (sdt == NULL)
17118f4a4ed9Spgoyette return EINVAL;
1712e802e6b6Sxtraeme
171335a3b0e4Spgoyette DPRINTFOBJ(("%s: sensor #%d units=%d (%s)\n", __func__, edata->sensor,
171435a3b0e4Spgoyette sdt->type, sdt->desc));
1715f7ad7038Spgoyette
1716e76f489bSpgoyette error = sme_sensor_upstring(dict, "type", sdt->desc);
17171b3709ecSxtraeme if (error)
171835a3b0e4Spgoyette return (-error);
17191b3709ecSxtraeme
17205960b5e5Spgoyette if (value_update) {
17215960b5e5Spgoyette /*
17225960b5e5Spgoyette * update sensor's current value.
17235960b5e5Spgoyette */
17245960b5e5Spgoyette error = sme_sensor_upint32(dict, "cur-value", edata->value_cur);
17255960b5e5Spgoyette if (error)
17265960b5e5Spgoyette return error;
17275960b5e5Spgoyette }
17285960b5e5Spgoyette
172931962fc6Sxtraeme /*
173035a3b0e4Spgoyette * Battery charge and Indicator types do not
173135a3b0e4Spgoyette * need the remaining objects, so skip them.
173231962fc6Sxtraeme */
173335a3b0e4Spgoyette if (edata->units == ENVSYS_INDICATOR ||
17344e10a848Sxtraeme edata->units == ENVSYS_BATTERY_CHARGE)
173535a3b0e4Spgoyette return error;
1736bf4558f8Sxtraeme
173731962fc6Sxtraeme /*
173831962fc6Sxtraeme * update sensor flags.
173931962fc6Sxtraeme */
1740bf9c6587Sxtraeme if (edata->flags & ENVSYS_FPERCENT) {
174135a3b0e4Spgoyette error = sme_sensor_upbool(dict, "want-percentage", true);
1742bf9c6587Sxtraeme if (error)
174335a3b0e4Spgoyette return error;
1744bf4558f8Sxtraeme }
1745bf4558f8Sxtraeme
174635a3b0e4Spgoyette if (value_update) {
174735a3b0e4Spgoyette /*
174877b2e2fcSpgoyette * update sensor's {max,min}-value.
174931962fc6Sxtraeme */
1750bf9c6587Sxtraeme if (edata->flags & ENVSYS_FVALID_MAX) {
175135a3b0e4Spgoyette error = sme_sensor_upint32(dict, "max-value",
1752bf9c6587Sxtraeme edata->value_max);
1753bf9c6587Sxtraeme if (error)
175435a3b0e4Spgoyette return error;
1755bf9c6587Sxtraeme }
1756bf4558f8Sxtraeme
1757bf9c6587Sxtraeme if (edata->flags & ENVSYS_FVALID_MIN) {
175835a3b0e4Spgoyette error = sme_sensor_upint32(dict, "min-value",
1759bf9c6587Sxtraeme edata->value_min);
1760bf9c6587Sxtraeme if (error)
176135a3b0e4Spgoyette return error;
1762bf9c6587Sxtraeme }
1763bf4558f8Sxtraeme
176431962fc6Sxtraeme /*
176531962fc6Sxtraeme * update 'rpms' only for ENVSYS_SFANRPM sensors.
176631962fc6Sxtraeme */
1767bf9c6587Sxtraeme if (edata->units == ENVSYS_SFANRPM) {
176835a3b0e4Spgoyette error = sme_sensor_upuint32(dict, "rpms", edata->rpms);
1769bf9c6587Sxtraeme if (error)
177035a3b0e4Spgoyette return error;
1771bf9c6587Sxtraeme }
1772bf4558f8Sxtraeme
177331962fc6Sxtraeme /*
177431962fc6Sxtraeme * update 'rfact' only for ENVSYS_SVOLTS_[AD]C sensors.
177531962fc6Sxtraeme */
1776bf4558f8Sxtraeme if (edata->units == ENVSYS_SVOLTS_AC ||
1777bf4558f8Sxtraeme edata->units == ENVSYS_SVOLTS_DC) {
177835a3b0e4Spgoyette error = sme_sensor_upint32(dict, "rfact", edata->rfact);
1779bf9c6587Sxtraeme if (error)
178035a3b0e4Spgoyette return error;
178135a3b0e4Spgoyette }
1782bf4558f8Sxtraeme }
1783bf4558f8Sxtraeme
178431962fc6Sxtraeme /*
178531962fc6Sxtraeme * update 'drive-state' only for ENVSYS_DRIVE sensors.
178631962fc6Sxtraeme */
1787bf4558f8Sxtraeme if (edata->units == ENVSYS_DRIVE) {
1788e76f489bSpgoyette sdt = sme_find_table_entry(SME_DESC_DRIVE_STATES,
1789e76f489bSpgoyette edata->value_cur);
17908f4a4ed9Spgoyette if (sdt == NULL)
17918f4a4ed9Spgoyette return EINVAL;
179235a3b0e4Spgoyette error = sme_sensor_upstring(dict, "drive-state", sdt->desc);
17935b53183eSxtraeme if (error)
179435a3b0e4Spgoyette return error;
17955b53183eSxtraeme }
17965b53183eSxtraeme
179731962fc6Sxtraeme /*
179831962fc6Sxtraeme * update 'battery-capacity' only for ENVSYS_BATTERY_CAPACITY
179931962fc6Sxtraeme * sensors.
180031962fc6Sxtraeme */
18014e10a848Sxtraeme if (edata->units == ENVSYS_BATTERY_CAPACITY) {
1802e76f489bSpgoyette sdt = sme_find_table_entry(SME_DESC_BATTERY_CAPACITY,
1803e76f489bSpgoyette edata->value_cur);
18048f4a4ed9Spgoyette if (sdt == NULL)
18058f4a4ed9Spgoyette return EINVAL;
1806e76f489bSpgoyette error = sme_sensor_upstring(dict, "battery-capacity",
1807e76f489bSpgoyette sdt->desc);
1808d78abcefSxtraeme if (error)
180935a3b0e4Spgoyette return error;
1810bf4558f8Sxtraeme }
1811bf4558f8Sxtraeme
1812bf4558f8Sxtraeme return error;
1813bf4558f8Sxtraeme }
1814bf4558f8Sxtraeme
1815bf4558f8Sxtraeme /*
1816bf4558f8Sxtraeme * sme_userset_dictionary:
1817bf4558f8Sxtraeme *
1818*9f981eecSandvar * + Parse the userland dictionary and run the appropriate tasks
181931962fc6Sxtraeme * that were specified.
1820bf4558f8Sxtraeme */
1821bf4558f8Sxtraeme int
sme_userset_dictionary(struct sysmon_envsys * sme,prop_dictionary_t udict,prop_array_t array)1822bf4558f8Sxtraeme sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
1823bf4558f8Sxtraeme prop_array_t array)
1824bf4558f8Sxtraeme {
1825e76f489bSpgoyette const struct sme_descr_entry *sdt;
182631962fc6Sxtraeme envsys_data_t *edata;
182731962fc6Sxtraeme prop_dictionary_t dict, tdict = NULL;
182831962fc6Sxtraeme prop_object_t obj, obj1, obj2, tobj = NULL;
182991504364Spgoyette uint32_t props;
183031962fc6Sxtraeme uint64_t refresh_timo = 0;
1831c2357777Spgoyette sysmon_envsys_lim_t lims;
183231962fc6Sxtraeme int i, error = 0;
183331962fc6Sxtraeme const char *blah;
1834bf4558f8Sxtraeme bool targetfound = false;
1835bf4558f8Sxtraeme
183631962fc6Sxtraeme /*
183731962fc6Sxtraeme * The user wanted to change the refresh timeout value for this
183831962fc6Sxtraeme * device.
183931962fc6Sxtraeme *
184031962fc6Sxtraeme * Get the 'device-properties' object from the userland dictionary.
184131962fc6Sxtraeme */
184231962fc6Sxtraeme obj = prop_dictionary_get(udict, "device-properties");
184331962fc6Sxtraeme if (obj && prop_object_type(obj) == PROP_TYPE_DICTIONARY) {
184431962fc6Sxtraeme /*
184531962fc6Sxtraeme * Get the 'refresh-timeout' property for this device.
184631962fc6Sxtraeme */
184731962fc6Sxtraeme obj1 = prop_dictionary_get(obj, "refresh-timeout");
184831962fc6Sxtraeme if (obj1 && prop_object_type(obj1) == PROP_TYPE_NUMBER) {
184931962fc6Sxtraeme targetfound = true;
185031962fc6Sxtraeme refresh_timo =
1851a2b798fdSthorpej prop_number_unsigned_value(obj1);
185231962fc6Sxtraeme if (refresh_timo < 1)
185331962fc6Sxtraeme error = EINVAL;
18545ee4eba8Sxtraeme else {
1855d7a982b2Sriastradh mutex_enter(&sme->sme_work_mtx);
185659fe847eSpgoyette if (sme->sme_events_timeout != refresh_timo) {
185731962fc6Sxtraeme sme->sme_events_timeout = refresh_timo;
185859fe847eSpgoyette sme_schedule_callout(sme);
185959fe847eSpgoyette }
1860d7a982b2Sriastradh mutex_exit(&sme->sme_work_mtx);
186131962fc6Sxtraeme }
18625ee4eba8Sxtraeme }
18635ee4eba8Sxtraeme return error;
186431962fc6Sxtraeme
186531962fc6Sxtraeme } else if (!obj) {
186631962fc6Sxtraeme /*
186731962fc6Sxtraeme * Get sensor's index from userland dictionary.
186831962fc6Sxtraeme */
18696c4da82bSxtraeme obj = prop_dictionary_get(udict, "index");
187031962fc6Sxtraeme if (!obj)
18715ee4eba8Sxtraeme return EINVAL;
1872bf4558f8Sxtraeme if (prop_object_type(obj) != PROP_TYPE_STRING) {
187331962fc6Sxtraeme DPRINTF(("%s: 'index' not a string\n", __func__));
1874bf4558f8Sxtraeme return EINVAL;
1875bf4558f8Sxtraeme }
187631962fc6Sxtraeme } else
187731962fc6Sxtraeme return EINVAL;
1878bf4558f8Sxtraeme
18796c4da82bSxtraeme /*
18805ee4eba8Sxtraeme * Don't bother with locking when traversing the queue,
18815ee4eba8Sxtraeme * the device is already marked as busy; if a sensor
18825ee4eba8Sxtraeme * is going to be removed or added it will have to wait.
18836c4da82bSxtraeme */
188431962fc6Sxtraeme TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
188531962fc6Sxtraeme /*
188631962fc6Sxtraeme * Get a dictionary and check if it's our sensor by checking
188731962fc6Sxtraeme * at its index position.
188831962fc6Sxtraeme */
188931962fc6Sxtraeme dict = prop_array_get(array, edata->sensor);
18906c4da82bSxtraeme obj1 = prop_dictionary_get(dict, "index");
1891bf4558f8Sxtraeme
189231962fc6Sxtraeme /*
189331962fc6Sxtraeme * is it our sensor?
189431962fc6Sxtraeme */
1895bf4558f8Sxtraeme if (!prop_string_equals(obj1, obj))
1896bf4558f8Sxtraeme continue;
1897bf4558f8Sxtraeme
189891504364Spgoyette props = 0;
1899c2357777Spgoyette
1900bf4558f8Sxtraeme /*
1901bf4558f8Sxtraeme * Check if a new description operation was
1902bf4558f8Sxtraeme * requested by the user and set new description.
1903bf4558f8Sxtraeme */
190431962fc6Sxtraeme obj2 = prop_dictionary_get(udict, "description");
190531962fc6Sxtraeme if (obj2 && prop_object_type(obj2) == PROP_TYPE_STRING) {
1906bf4558f8Sxtraeme targetfound = true;
1907814a7798Sthorpej blah = prop_string_value(obj2);
1908fc370c98Sxtraeme
190931962fc6Sxtraeme /*
191031962fc6Sxtraeme * Check for duplicate description.
191131962fc6Sxtraeme */
1912fc370c98Sxtraeme for (i = 0; i < sme->sme_nsensors; i++) {
1913fc370c98Sxtraeme if (i == edata->sensor)
1914fc370c98Sxtraeme continue;
191531962fc6Sxtraeme tdict = prop_array_get(array, i);
191631962fc6Sxtraeme tobj =
191731962fc6Sxtraeme prop_dictionary_get(tdict, "description");
19185ee4eba8Sxtraeme if (prop_string_equals(obj2, tobj)) {
19195ee4eba8Sxtraeme error = EEXIST;
19205ee4eba8Sxtraeme goto out;
19215ee4eba8Sxtraeme }
1922d11db10fSxtraeme }
1923fc370c98Sxtraeme
192431962fc6Sxtraeme /*
192531962fc6Sxtraeme * Update the object in dictionary.
192631962fc6Sxtraeme */
19275ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
1928b2537bf1Sxtraeme error = sme_sensor_upstring(dict,
1929bf9c6587Sxtraeme "description",
1930bf9c6587Sxtraeme blah);
19315ee4eba8Sxtraeme if (error) {
19325ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
19335ee4eba8Sxtraeme goto out;
19345ee4eba8Sxtraeme }
1935bf4558f8Sxtraeme
193631962fc6Sxtraeme DPRINTF(("%s: sensor%d changed desc to: %s\n",
193731962fc6Sxtraeme __func__, edata->sensor, blah));
1938f7ad7038Spgoyette edata->upropset |= PROP_DESC;
19395ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
1940bf4558f8Sxtraeme }
1941bf4558f8Sxtraeme
19426c4da82bSxtraeme /*
19436c4da82bSxtraeme * did the user want to change the rfact?
19446c4da82bSxtraeme */
19456c4da82bSxtraeme obj2 = prop_dictionary_get(udict, "rfact");
194631962fc6Sxtraeme if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
1947bf4558f8Sxtraeme targetfound = true;
19486c4da82bSxtraeme if (edata->flags & ENVSYS_FCHANGERFACT) {
19495ee4eba8Sxtraeme mutex_enter(&sme->sme_mtx);
1950814a7798Sthorpej edata->rfact = prop_number_signed_value(obj2);
1951f7ad7038Spgoyette edata->upropset |= PROP_RFACT;
19525ee4eba8Sxtraeme mutex_exit(&sme->sme_mtx);
195331962fc6Sxtraeme DPRINTF(("%s: sensor%d changed rfact to %d\n",
195431962fc6Sxtraeme __func__, edata->sensor, edata->rfact));
19555ee4eba8Sxtraeme } else {
19565ee4eba8Sxtraeme error = ENOTSUP;
19575ee4eba8Sxtraeme goto out;
19585ee4eba8Sxtraeme }
19596c4da82bSxtraeme }
1960bf4558f8Sxtraeme
1961e76f489bSpgoyette sdt = sme_find_table_entry(SME_DESC_UNITS, edata->units);
1962bf4558f8Sxtraeme
19636c4da82bSxtraeme /*
19646c4da82bSxtraeme * did the user want to set a critical capacity event?
19656c4da82bSxtraeme */
1966bf4558f8Sxtraeme obj2 = prop_dictionary_get(udict, "critical-capacity");
196731962fc6Sxtraeme if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
1968bf4558f8Sxtraeme targetfound = true;
1969814a7798Sthorpej lims.sel_critmin = prop_number_signed_value(obj2);
197091504364Spgoyette props |= PROP_BATTCAP;
1971bf4558f8Sxtraeme }
1972bf4558f8Sxtraeme
19736c4da82bSxtraeme /*
19746d65ba83Spgoyette * did the user want to set a warning capacity event?
19756d65ba83Spgoyette */
19766d65ba83Spgoyette obj2 = prop_dictionary_get(udict, "warning-capacity");
19776d65ba83Spgoyette if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
19786d65ba83Spgoyette targetfound = true;
1979814a7798Sthorpej lims.sel_warnmin = prop_number_signed_value(obj2);
198091504364Spgoyette props |= PROP_BATTWARN;
19816d65ba83Spgoyette }
19826d65ba83Spgoyette
19836d65ba83Spgoyette /*
19848844275bSpgoyette * did the user want to set a high capacity event?
19858844275bSpgoyette */
19868844275bSpgoyette obj2 = prop_dictionary_get(udict, "high-capacity");
19878844275bSpgoyette if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
19888844275bSpgoyette targetfound = true;
1989814a7798Sthorpej lims.sel_warnmin = prop_number_signed_value(obj2);
19908844275bSpgoyette props |= PROP_BATTHIGH;
19918844275bSpgoyette }
19928844275bSpgoyette
19938844275bSpgoyette /*
19948844275bSpgoyette * did the user want to set a maximum capacity event?
19958844275bSpgoyette */
19968844275bSpgoyette obj2 = prop_dictionary_get(udict, "maximum-capacity");
19978844275bSpgoyette if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
19988844275bSpgoyette targetfound = true;
1999814a7798Sthorpej lims.sel_warnmin = prop_number_signed_value(obj2);
20008844275bSpgoyette props |= PROP_BATTMAX;
20018844275bSpgoyette }
20028844275bSpgoyette
20038844275bSpgoyette /*
20046c4da82bSxtraeme * did the user want to set a critical max event?
20056c4da82bSxtraeme */
20066c4da82bSxtraeme obj2 = prop_dictionary_get(udict, "critical-max");
200731962fc6Sxtraeme if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
2008bf4558f8Sxtraeme targetfound = true;
2009814a7798Sthorpej lims.sel_critmax = prop_number_signed_value(obj2);
201091504364Spgoyette props |= PROP_CRITMAX;
2011bf4558f8Sxtraeme }
2012bf4558f8Sxtraeme
20136c4da82bSxtraeme /*
20146d65ba83Spgoyette * did the user want to set a warning max event?
20156d65ba83Spgoyette */
20166d65ba83Spgoyette obj2 = prop_dictionary_get(udict, "warning-max");
20176d65ba83Spgoyette if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
20186d65ba83Spgoyette targetfound = true;
2019814a7798Sthorpej lims.sel_warnmax = prop_number_signed_value(obj2);
202091504364Spgoyette props |= PROP_WARNMAX;
20216d65ba83Spgoyette }
20226d65ba83Spgoyette
20236d65ba83Spgoyette /*
20246c4da82bSxtraeme * did the user want to set a critical min event?
20256c4da82bSxtraeme */
20266c4da82bSxtraeme obj2 = prop_dictionary_get(udict, "critical-min");
202731962fc6Sxtraeme if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
2028bf4558f8Sxtraeme targetfound = true;
2029814a7798Sthorpej lims.sel_critmin = prop_number_signed_value(obj2);
203091504364Spgoyette props |= PROP_CRITMIN;
2031bf4558f8Sxtraeme }
20326c4da82bSxtraeme
20336c4da82bSxtraeme /*
20346d65ba83Spgoyette * did the user want to set a warning min event?
20356d65ba83Spgoyette */
20366d65ba83Spgoyette obj2 = prop_dictionary_get(udict, "warning-min");
20376d65ba83Spgoyette if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
20386d65ba83Spgoyette targetfound = true;
2039814a7798Sthorpej lims.sel_warnmin = prop_number_signed_value(obj2);
204091504364Spgoyette props |= PROP_WARNMIN;
2041f7ad7038Spgoyette }
2042f7ad7038Spgoyette
2043063727a4Spgoyette if (props && (edata->flags & ENVSYS_FMONNOTSUPP) != 0) {
2044aaabf34dSpgoyette error = ENOTSUP;
2045aaabf34dSpgoyette goto out;
2046aaabf34dSpgoyette }
2047063727a4Spgoyette if (props || (edata->flags & ENVSYS_FHAS_ENTROPY) != 0) {
2048c2357777Spgoyette error = sme_event_register(dict, edata, sme, &lims,
204991504364Spgoyette props,
2050f7ad7038Spgoyette (edata->flags & ENVSYS_FPERCENT)?
2051f7ad7038Spgoyette PENVSYS_EVENT_CAPACITY:
2052f7ad7038Spgoyette PENVSYS_EVENT_LIMITS,
2053e76f489bSpgoyette sdt->crittype);
20546d65ba83Spgoyette if (error == EEXIST)
20556d65ba83Spgoyette error = 0;
20566d65ba83Spgoyette if (error)
20576d65ba83Spgoyette goto out;
20586d65ba83Spgoyette }
20596d65ba83Spgoyette
20606d65ba83Spgoyette /*
20616c4da82bSxtraeme * All objects in dictionary were processed.
20626c4da82bSxtraeme */
20636c4da82bSxtraeme break;
2064bf4558f8Sxtraeme }
2065bf4558f8Sxtraeme
206631962fc6Sxtraeme out:
206731962fc6Sxtraeme /*
206831962fc6Sxtraeme * invalid target? return the error.
206931962fc6Sxtraeme */
2070bf4558f8Sxtraeme if (!targetfound)
2071bf4558f8Sxtraeme error = EINVAL;
2072bf4558f8Sxtraeme
2073bf4558f8Sxtraeme return error;
2074e67f5e66Sthorpej }
20751de3adb5Spgoyette
20761de3adb5Spgoyette /*
20771de3adb5Spgoyette * + sysmon_envsys_foreach_sensor
20781de3adb5Spgoyette *
20791de3adb5Spgoyette * Walk through the devices' sensor lists and execute the callback.
20801de3adb5Spgoyette * If the callback returns false, the remainder of the current
20811de3adb5Spgoyette * device's sensors are skipped.
20821de3adb5Spgoyette */
20831de3adb5Spgoyette void
sysmon_envsys_foreach_sensor(sysmon_envsys_callback_t func,void * arg,bool refresh)2084730da129Spgoyette sysmon_envsys_foreach_sensor(sysmon_envsys_callback_t func, void *arg,
2085730da129Spgoyette bool refresh)
20861de3adb5Spgoyette {
20871de3adb5Spgoyette struct sysmon_envsys *sme;
20881de3adb5Spgoyette envsys_data_t *sensor;
20891de3adb5Spgoyette
20901de3adb5Spgoyette mutex_enter(&sme_global_mtx);
20911de3adb5Spgoyette LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
20921de3adb5Spgoyette
20935dbc4fadSpgoyette sysmon_envsys_acquire(sme, false);
20941de3adb5Spgoyette TAILQ_FOREACH(sensor, &sme->sme_sensors_list, sensors_head) {
2095063727a4Spgoyette if (refresh) {
20965dbc4fadSpgoyette mutex_enter(&sme->sme_mtx);
209787d1d221Spgoyette sysmon_envsys_refresh_sensor(sme, sensor);
20985dbc4fadSpgoyette mutex_exit(&sme->sme_mtx);
20995dbc4fadSpgoyette }
21006c1f2c41Spgoyette if (!(*func)(sme, sensor, arg))
21011de3adb5Spgoyette break;
21021de3adb5Spgoyette }
21035dbc4fadSpgoyette sysmon_envsys_release(sme, false);
21041de3adb5Spgoyette }
21051de3adb5Spgoyette mutex_exit(&sme_global_mtx);
21061de3adb5Spgoyette }
210787d1d221Spgoyette
210887d1d221Spgoyette /*
210987d1d221Spgoyette * Call the sensor's refresh function, and collect/stir entropy
211087d1d221Spgoyette */
211187d1d221Spgoyette void
sysmon_envsys_refresh_sensor(struct sysmon_envsys * sme,envsys_data_t * edata)211287d1d221Spgoyette sysmon_envsys_refresh_sensor(struct sysmon_envsys *sme, envsys_data_t *edata)
211387d1d221Spgoyette {
211487d1d221Spgoyette
2115063727a4Spgoyette if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0)
211687d1d221Spgoyette (*sme->sme_refresh)(sme, edata);
2117063727a4Spgoyette
2118063727a4Spgoyette if (edata->flags & ENVSYS_FHAS_ENTROPY &&
211987d1d221Spgoyette edata->state != ENVSYS_SINVALID &&
2120063727a4Spgoyette edata->value_prev != edata->value_cur)
212187d1d221Spgoyette rnd_add_uint32(&edata->rnd_src, edata->value_cur);
2122063727a4Spgoyette edata->value_prev = edata->value_cur;
212387d1d221Spgoyette }
21248061eedeSpgoyette
212554853d3dSriastradh static int
sysmon_envsys_modcmd(modcmd_t cmd,void * arg)21268061eedeSpgoyette sysmon_envsys_modcmd(modcmd_t cmd, void *arg)
21278061eedeSpgoyette {
21288061eedeSpgoyette int ret;
21298061eedeSpgoyette
21308061eedeSpgoyette switch (cmd) {
21318061eedeSpgoyette case MODULE_CMD_INIT:
21328061eedeSpgoyette ret = sysmon_envsys_init();
21338061eedeSpgoyette break;
21348061eedeSpgoyette case MODULE_CMD_FINI:
21358061eedeSpgoyette ret = sysmon_envsys_fini();
21368061eedeSpgoyette break;
21378061eedeSpgoyette case MODULE_CMD_STAT:
21388061eedeSpgoyette default:
21398061eedeSpgoyette ret = ENOTTY;
21408061eedeSpgoyette }
21418061eedeSpgoyette
21428061eedeSpgoyette return ret;
21438061eedeSpgoyette }
2144