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