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