1 /* $NetBSD: sysmon_envsys.c,v 1.1 2000/11/05 04:06:13 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 * Environmental sensor framework for sysmon. Hardware monitors 38 * such as the LM78 and VIA 82C686A (or even ACPI, eventually) can 39 * register themselves to provide backplane fan and temperature 40 * information, etc. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/conf.h> 45 #include <sys/errno.h> 46 #include <sys/fcntl.h> 47 #include <sys/lock.h> 48 #include <sys/kernel.h> 49 #include <sys/systm.h> 50 #include <sys/proc.h> 51 52 #include <dev/sysmon/sysmonvar.h> 53 54 /* 55 * We run at ENVSYS version 1. 56 */ 57 #define SYSMON_ENVSYS_VERSION (1 * 1000) 58 59 struct lock sysmon_envsys_lock; 60 61 LIST_HEAD(, sysmon_envsys) sysmon_envsys_list = 62 LIST_HEAD_INITIALIZER(&sysmon_envsys_list); 63 struct simplelock sysmon_envsys_list_slock = SIMPLELOCK_INITIALIZER; 64 u_int sysmon_envsys_next_sensor_index; 65 66 int sysmon_envsys_initialized; 67 struct simplelock sysmon_envsys_initialized_slock = SIMPLELOCK_INITIALIZER; 68 69 void sysmon_envsys_init(void); 70 71 int sysmonioctl_envsys(dev_t, u_long, caddr_t, int, struct proc *); 72 int sysmonioctl_wdog(dev_t, u_long, caddr_t, int, struct proc *); 73 74 struct sysmon_envsys *sysmon_envsys_find(u_int); 75 void sysmon_envsys_release(struct sysmon_envsys *); 76 77 /* 78 * sysmon_envsys_init: 79 * 80 * Initialize the system monitor. 81 */ 82 void 83 sysmon_envsys_init(void) 84 { 85 86 lockinit(&sysmon_envsys_lock, PWAIT|PCATCH, "smenv", 0, 0); 87 sysmon_envsys_initialized = 1; 88 } 89 90 /* 91 * sysmonopen_envsys: 92 * 93 * Open the system monitor device. 94 */ 95 int 96 sysmonopen_envsys(dev_t dev, int flag, int mode, struct proc *p) 97 { 98 int error = 0; 99 100 simple_lock(&sysmon_envsys_initialized_slock); 101 if (sysmon_envsys_initialized == 0) 102 sysmon_envsys_init(); 103 104 error = lockmgr(&sysmon_envsys_lock, 105 LK_EXCLUSIVE | LK_INTERLOCK | 106 ((flag & O_NONBLOCK) ? LK_NOWAIT : 0), 107 &sysmon_envsys_initialized_slock); 108 109 return (error); 110 } 111 112 /* 113 * sysmonclose_envsys: 114 * 115 * Close the system monitor device. 116 */ 117 int 118 sysmonclose_envsys(dev_t dev, int flag, int mode, struct proc *p) 119 { 120 121 (void) lockmgr(&sysmon_envsys_lock, LK_RELEASE, NULL); 122 return (0); 123 } 124 125 /* 126 * sysmonioctl_envsys: 127 * 128 * Perform an envsys control request. 129 */ 130 int 131 sysmonioctl_envsys(dev_t dev, u_long cmd, caddr_t data, int flag, 132 struct proc *p) 133 { 134 struct sysmon_envsys *sme; 135 int error = 0; 136 u_int oidx; 137 138 switch (cmd) { 139 /* 140 * For ENVSYS commands, we translate the absolute sensor index 141 * to a device-relative sensor index. 142 */ 143 case ENVSYS_VERSION: 144 *(int32_t *)data = SYSMON_ENVSYS_VERSION; 145 break; 146 147 case ENVSYS_GRANGE: 148 { 149 struct envsys_range *rng = (void *) data; 150 151 sme = sysmon_envsys_find(0); /* XXX */ 152 if (sme == NULL) { 153 /* Return empty range for `no sensors'. */ 154 rng->low = 1; 155 rng->high = 0; 156 break; 157 } 158 159 if (rng->units < ENVSYS_NSENSORS) 160 *rng = sme->sme_ranges[rng->units]; 161 else { 162 /* Return empty range for unsupported sensor types. */ 163 rng->low = 1; 164 rng->high = 0; 165 } 166 sysmon_envsys_release(sme); 167 break; 168 } 169 170 case ENVSYS_GTREDATA: 171 { 172 struct envsys_tre_data *tred = (void *) data; 173 174 tred->validflags = 0; 175 176 sme = sysmon_envsys_find(tred->sensor); 177 if (sme == NULL) 178 break; 179 oidx = tred->sensor; 180 tred->sensor = SME_SENSOR_IDX(sme, tred->sensor); 181 if (tred->sensor < sme->sme_nsensors) 182 error = (*sme->sme_gtredata)(sme, tred); 183 tred->sensor = oidx; 184 sysmon_envsys_release(sme); 185 break; 186 } 187 188 case ENVSYS_STREINFO: 189 { 190 struct envsys_basic_info *binfo = (void *) data; 191 192 sme = sysmon_envsys_find(binfo->sensor); 193 if (sme == NULL) { 194 binfo->validflags = 0; 195 break; 196 } 197 oidx = binfo->sensor; 198 binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor); 199 if (binfo->sensor < sme->sme_nsensors) 200 error = (*sme->sme_streinfo)(sme, binfo); 201 else 202 binfo->validflags = 0; 203 binfo->sensor = oidx; 204 sysmon_envsys_release(sme); 205 break; 206 } 207 208 case ENVSYS_GTREINFO: 209 { 210 struct envsys_basic_info *binfo = (void *) data; 211 212 binfo->validflags = 0; 213 214 sme = sysmon_envsys_find(binfo->sensor); 215 if (sme == NULL) 216 break; 217 oidx = binfo->sensor; 218 binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor); 219 if (binfo->sensor < sme->sme_nsensors) 220 *binfo = sme->sme_sensor_info[binfo->sensor]; 221 binfo->sensor = oidx; 222 sysmon_envsys_release(sme); 223 break; 224 } 225 226 default: 227 error = ENOTTY; 228 } 229 230 return (error); 231 } 232 233 /* 234 * sysmon_envsys_register: 235 * 236 * Register an ENVSYS device. 237 */ 238 int 239 sysmon_envsys_register(struct sysmon_envsys *sme) 240 { 241 int error = 0; 242 243 simple_lock(&sysmon_envsys_list_slock); 244 245 /* XXX Only get to register one, for now. */ 246 if (LIST_FIRST(&sysmon_envsys_list) != NULL) { 247 error = EEXIST; 248 goto out; 249 } 250 251 if (sme->sme_envsys_version != SYSMON_ENVSYS_VERSION) { 252 error = EINVAL; 253 goto out; 254 } 255 256 sme->sme_fsensor = sysmon_envsys_next_sensor_index; 257 sysmon_envsys_next_sensor_index += sme->sme_nsensors; 258 LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list); 259 260 out: 261 simple_unlock(&sysmon_envsys_list_slock); 262 return (error); 263 } 264 265 /* 266 * sysmon_envsys_unregister: 267 * 268 * Unregister an ENVSYS device. 269 */ 270 void 271 sysmon_envsys_unregister(struct sysmon_envsys *sme) 272 { 273 274 simple_lock(&sysmon_envsys_list_slock); 275 LIST_REMOVE(sme, sme_list); 276 simple_unlock(&sysmon_envsys_list_slock); 277 } 278 279 /* 280 * sysmon_envsys_find: 281 * 282 * Find an ENVSYS device. The list remains locked upon 283 * a match. 284 */ 285 struct sysmon_envsys * 286 sysmon_envsys_find(u_int idx) 287 { 288 struct sysmon_envsys *sme; 289 290 simple_lock(&sysmon_envsys_list_slock); 291 292 for (sme = LIST_FIRST(&sysmon_envsys_list); sme != NULL; 293 sme = LIST_NEXT(sme, sme_list)) { 294 if (idx >= sme->sme_fsensor && 295 idx < (sme->sme_fsensor + sme->sme_nsensors)) 296 return (sme); 297 } 298 299 simple_unlock(&sysmon_envsys_list_slock); 300 return (NULL); 301 } 302 303 /* 304 * sysmon_envsys_release: 305 * 306 * Release an ENVSYS device. 307 */ 308 /* ARGSUSED */ 309 void 310 sysmon_envsys_release(struct sysmon_envsys *sme) 311 { 312 313 simple_unlock(&sysmon_envsys_list_slock); 314 } 315