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