1 /* $NetBSD: sysmon.c,v 1.2 2000/06/28 06:51:17 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Zembu Labs, Inc. 5 * All rights reserved. 6 * 7 * Author: Jason R. Thorpe <thorpej@zembu.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Zembu Labs, Inc. 20 * 4. Neither the name of Zembu Labs nor the names of its employees may 21 * be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS 25 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR- 26 * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- 27 * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* 37 * Clearing house for system monitoring hardware. This pseudo-device 38 * is a place where hardware monitors such as the LM78 and VIA 82C686A 39 * (or even ACPI, eventually) can register themselves to provide 40 * backplane fan and temperature information, etc. 41 * 42 * Eventually, we will also provide a way for a hardware watchdog timer 43 * to hook itself up here (with an option to fall back on a software 44 * watchdog timer if hardware is not available). 45 */ 46 47 #include <sys/param.h> 48 #include <sys/conf.h> 49 #include <sys/errno.h> 50 #include <sys/fcntl.h> 51 #include <sys/lock.h> 52 53 #include <dev/sysmon/sysmonvar.h> 54 55 /* 56 * We run at ENVSYS version 1. 57 */ 58 #define SYSMON_ENVSYS_VERSION (1 * 1000) 59 60 struct lock sysmon_lock; 61 62 LIST_HEAD(, sysmon_envsys) sysmon_envsys_list; 63 struct simplelock sysmon_envsys_list_slock = SIMPLELOCK_INITIALIZER; 64 u_int sysmon_envsys_next_sensor_index; 65 66 int sysmon_initialized; 67 struct simplelock sysmon_initialized_slock = SIMPLELOCK_INITIALIZER; 68 69 cdev_decl(sysmon); 70 71 void sysmon_init(void); 72 73 struct sysmon_envsys *sysmon_envsys_find(u_int); 74 void sysmon_envsys_release(struct sysmon_envsys *); 75 76 /* 77 * sysmon_init: 78 * 79 * Initialize the system monitor. 80 */ 81 void 82 sysmon_init(void) 83 { 84 85 lockinit(&sysmon_lock, PWAIT|PCATCH, "sysmon", 0, 0); 86 sysmon_initialized = 1; 87 } 88 89 /* 90 * sysmonopen: 91 * 92 * Open the system monitor device. 93 */ 94 int 95 sysmonopen(dev_t dev, int flag, int mode, struct proc *p) 96 { 97 int error; 98 99 simple_lock(&sysmon_initialized_slock); 100 if (sysmon_initialized == 0) 101 sysmon_init(); 102 103 error = lockmgr(&sysmon_lock, 104 LK_EXCLUSIVE | LK_INTERLOCK | 105 ((flag & O_NONBLOCK) ? LK_NOWAIT : 0), &sysmon_initialized_slock); 106 107 return (error); 108 } 109 110 /* 111 * sysmonclose: 112 * 113 * Close the system monitor device. 114 */ 115 int 116 sysmonclose(dev_t dev, int flag, int mode, struct proc *p) 117 { 118 119 (void) lockmgr(&sysmon_lock, LK_RELEASE, NULL); 120 return (0); 121 } 122 123 /* 124 * sysmonioctl: 125 * 126 * Perform a control request. 127 */ 128 int 129 sysmonioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 130 { 131 struct sysmon_envsys *sme; 132 int error = 0; 133 u_int oidx; 134 135 switch (cmd) { 136 /* 137 * For ENVSYS commands, we translate the absolute sensor index 138 * to a device-relative sensor index. 139 */ 140 case ENVSYS_VERSION: 141 *(int32_t *)data = SYSMON_ENVSYS_VERSION; 142 break; 143 144 case ENVSYS_GRANGE: 145 { 146 struct envsys_range *rng = (void *) data; 147 148 sme = sysmon_envsys_find(0); /* XXX */ 149 if (sme == NULL) { 150 /* Return empty range for `no sensors'. */ 151 rng->low = 1; 152 rng->high = 0; 153 break; 154 } 155 156 if (rng->units < ENVSYS_NSENSORS) 157 *rng = sme->sme_ranges[rng->units]; 158 else { 159 /* Return empty range for unsupported sensor types. */ 160 rng->low = 1; 161 rng->high = 0; 162 } 163 sysmon_envsys_release(sme); 164 break; 165 } 166 167 case ENVSYS_GTREDATA: 168 { 169 struct envsys_tre_data *tred = (void *) data; 170 171 tred->validflags = 0; 172 173 sme = sysmon_envsys_find(tred->sensor); 174 if (sme == NULL) 175 break; 176 oidx = tred->sensor; 177 tred->sensor = SME_SENSOR_IDX(sme, tred->sensor); 178 if (tred->sensor < sme->sme_nsensors) 179 error = (*sme->sme_gtredata)(sme, tred); 180 tred->sensor = oidx; 181 sysmon_envsys_release(sme); 182 break; 183 } 184 185 case ENVSYS_STREINFO: 186 { 187 struct envsys_basic_info *binfo = (void *) data; 188 189 sme = sysmon_envsys_find(binfo->sensor); 190 if (sme == NULL) { 191 binfo->validflags = 0; 192 break; 193 } 194 oidx = binfo->sensor; 195 binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor); 196 if (binfo->sensor < sme->sme_nsensors) 197 error = (*sme->sme_streinfo)(sme, binfo); 198 else 199 binfo->validflags = 0; 200 binfo->sensor = oidx; 201 sysmon_envsys_release(sme); 202 break; 203 } 204 205 case ENVSYS_GTREINFO: 206 { 207 struct envsys_basic_info *binfo = (void *) data; 208 209 binfo->validflags = 0; 210 211 sme = sysmon_envsys_find(binfo->sensor); 212 if (sme == NULL) 213 break; 214 oidx = binfo->sensor; 215 binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor); 216 if (binfo->sensor < sme->sme_nsensors) 217 *binfo = sme->sme_sensor_info[binfo->sensor]; 218 binfo->sensor = oidx; 219 sysmon_envsys_release(sme); 220 break; 221 } 222 223 default: 224 error = ENOTTY; 225 } 226 227 return (error); 228 } 229 230 /* 231 * sysmon_envsys_register: 232 * 233 * Register an ENVSYS device. 234 */ 235 int 236 sysmon_envsys_register(struct sysmon_envsys *sme) 237 { 238 int error = 0; 239 240 simple_lock(&sysmon_envsys_list_slock); 241 242 /* XXX Only get to register one, for now. */ 243 if (LIST_FIRST(&sysmon_envsys_list) != NULL) { 244 error = EEXIST; 245 goto out; 246 } 247 248 if (sme->sme_envsys_version != SYSMON_ENVSYS_VERSION) { 249 error = EINVAL; 250 goto out; 251 } 252 253 sme->sme_fsensor = sysmon_envsys_next_sensor_index; 254 sysmon_envsys_next_sensor_index += sme->sme_nsensors; 255 LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list); 256 257 out: 258 simple_unlock(&sysmon_envsys_list_slock); 259 return (error); 260 } 261 262 /* 263 * sysmon_envsys_unregister: 264 * 265 * Unregister an ENVSYS device. 266 */ 267 void 268 sysmon_envsys_unregister(struct sysmon_envsys *sme) 269 { 270 271 simple_lock(&sysmon_envsys_list_slock); 272 LIST_REMOVE(sme, sme_list); 273 simple_unlock(&sysmon_envsys_list_slock); 274 } 275 276 /* 277 * sysmon_envsys_find: 278 * 279 * Find an ENVSYS device. The list remains locked upon 280 * a match. 281 */ 282 struct sysmon_envsys * 283 sysmon_envsys_find(u_int idx) 284 { 285 struct sysmon_envsys *sme; 286 287 simple_lock(&sysmon_envsys_list_slock); 288 289 for (sme = LIST_FIRST(&sysmon_envsys_list); sme != NULL; 290 sme = LIST_NEXT(sme, sme_list)) { 291 if (idx >= sme->sme_fsensor && 292 idx < (sme->sme_fsensor + sme->sme_nsensors)) 293 return (sme); 294 } 295 296 simple_unlock(&sysmon_envsys_list_slock); 297 return (NULL); 298 } 299 300 /* 301 * sysmon_envsys_release: 302 * 303 * Release an ENVSYS device. 304 */ 305 /* ARGSUSED */ 306 void 307 sysmon_envsys_release(struct sysmon_envsys *sme) 308 { 309 310 simple_unlock(&sysmon_envsys_list_slock); 311 } 312