1 /* $NetBSD: swsensor.c,v 1.7 2010/12/17 13:37:37 pooka Exp $ */ 2 /* 3 * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 16 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 24 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: swsensor.c,v 1.7 2010/12/17 13:37:37 pooka Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/sysctl.h> 36 37 #include <dev/sysmon/sysmonvar.h> 38 39 #include <prop/proplib.h> 40 41 #ifndef _MODULE 42 #include "opt_modular.h" 43 #endif 44 45 int swsensorattach(int); 46 47 static struct sysctllog *swsensor_sysctllog = NULL; 48 49 static int sensor_value_sysctl = 0; 50 51 static struct sysmon_envsys *swsensor_sme; 52 static envsys_data_t swsensor_edata; 53 54 static int32_t sw_sensor_value; 55 static int32_t sw_sensor_limit; 56 static int32_t sw_sensor_mode; 57 static int32_t sw_sensor_defprops; 58 sysmon_envsys_lim_t sw_sensor_deflims; 59 60 MODULE(MODULE_CLASS_DRIVER, swsensor, NULL); 61 62 /* 63 * Set-up the sysctl interface for setting the sensor's cur_value 64 */ 65 66 static 67 void 68 sysctl_swsensor_setup(void) 69 { 70 int ret; 71 int node_sysctl_num; 72 const struct sysctlnode *me = NULL; 73 74 KASSERT(swsensor_sysctllog == NULL); 75 76 ret = sysctl_createv(&swsensor_sysctllog, 0, NULL, &me, 77 CTLFLAG_READWRITE, 78 CTLTYPE_NODE, "swsensor", NULL, 79 NULL, 0, NULL, 0, 80 CTL_HW, CTL_CREATE, CTL_EOL); 81 if (ret != 0) 82 return; 83 84 node_sysctl_num = me->sysctl_num; 85 ret = sysctl_createv(&swsensor_sysctllog, 0, NULL, &me, 86 CTLFLAG_READWRITE, 87 CTLTYPE_INT, "cur_value", NULL, 88 NULL, 0, &sw_sensor_value, 0, 89 CTL_HW, node_sysctl_num, CTL_CREATE, CTL_EOL); 90 91 if (ret == 0) 92 sensor_value_sysctl = me->sysctl_num; 93 } 94 95 /* 96 * "Polling" routine to update sensor value 97 */ 98 static 99 void 100 swsensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 101 { 102 103 edata->value_cur = sw_sensor_value; 104 105 /* 106 * Set state. If we're handling the limits ourselves, do the 107 * compare; otherwise just assume the value is valid. 108 */ 109 if ((sw_sensor_mode == 2) && (edata->upropset & PROP_CRITMIN) && 110 (edata->upropset & PROP_DRIVER_LIMITS) && 111 (edata->value_cur < edata->limits.sel_critmin)) 112 edata->state = ENVSYS_SCRITUNDER; 113 else 114 edata->state = ENVSYS_SVALID; 115 } 116 117 /* 118 * Sensor get/set limit routines 119 */ 120 121 static void 122 swsensor_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 123 sysmon_envsys_lim_t *limits, uint32_t *props) 124 { 125 126 *props = PROP_CRITMIN | PROP_DRIVER_LIMITS; 127 limits->sel_critmin = sw_sensor_limit; 128 } 129 130 static void 131 swsensor_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 132 sysmon_envsys_lim_t *limits, uint32_t *props) 133 { 134 135 if (limits == NULL) { 136 limits = &sw_sensor_deflims; 137 props = &sw_sensor_defprops; 138 } 139 if (*props & PROP_CRITMIN) 140 sw_sensor_limit = limits->sel_critmin; 141 142 /* 143 * If the limit we can handle (crit-min) is set, and no 144 * other limit is set, tell sysmon that the driver will 145 * handle the limit checking. 146 */ 147 if ((*props & PROP_LIMITS) == PROP_CRITMIN) 148 *props |= PROP_DRIVER_LIMITS; 149 else 150 *props &= ~PROP_DRIVER_LIMITS; 151 } 152 153 /* 154 * Module management 155 */ 156 157 static 158 int 159 swsensor_init(void *arg) 160 { 161 int error; 162 prop_dictionary_t pd = (prop_dictionary_t)arg; 163 prop_object_t po = NULL; 164 165 swsensor_sme = sysmon_envsys_create(); 166 if (swsensor_sme == NULL) 167 return ENOTTY; 168 169 swsensor_sme->sme_name = "swsensor"; 170 swsensor_sme->sme_cookie = &swsensor_edata; 171 swsensor_sme->sme_refresh = swsensor_refresh; 172 swsensor_sme->sme_set_limits = NULL; 173 swsensor_sme->sme_get_limits = NULL; 174 175 /* See if prop dictionary supplies a sensor type */ 176 if (pd != NULL) 177 po = prop_dictionary_get(pd, "type"); 178 179 if (po != NULL && prop_object_type(po) == PROP_TYPE_NUMBER) 180 swsensor_edata.units = prop_number_integer_value(po); 181 else 182 swsensor_edata.units = ENVSYS_INTEGER; 183 184 /* See if prop dictionary supplies sensor flags */ 185 if (pd != NULL) 186 po = prop_dictionary_get(pd, "flags"); 187 188 if (po != NULL && prop_object_type(po) == PROP_TYPE_NUMBER) 189 swsensor_edata.flags = prop_number_integer_value(po); 190 else 191 swsensor_edata.flags = 0; 192 193 /* 194 * Get requested sensor limit behavior 195 * 0 - simple sensor, no hw limits 196 * 1 - simple sensor, hw provides an initial limit 197 * 2 - complex sensor, hw provides settable limits and 198 * does its own limit checking 199 */ 200 if (pd != NULL) 201 po = prop_dictionary_get(pd, "mode"); 202 203 if (po != NULL && prop_object_type(po) == PROP_TYPE_NUMBER) { 204 sw_sensor_mode = prop_number_integer_value(po); 205 if (sw_sensor_mode > 2) 206 sw_sensor_mode = 2; 207 } else 208 sw_sensor_mode = 0; 209 210 if (sw_sensor_mode >= 1) 211 swsensor_sme->sme_get_limits = swsensor_get_limits; 212 213 if (sw_sensor_mode == 2) 214 swsensor_sme->sme_set_limits = swsensor_set_limits; 215 216 /* See if a limit value was provided - if not, use 0 */ 217 if (sw_sensor_mode != 0) { 218 swsensor_edata.flags |= ENVSYS_FMONLIMITS; 219 sw_sensor_limit = 0; 220 if (pd != NULL) 221 po = prop_dictionary_get(pd, "limit"); 222 223 if (po != NULL && prop_object_type(po) == PROP_TYPE_NUMBER) 224 sw_sensor_limit = prop_number_integer_value(po); 225 226 swsensor_get_limits(swsensor_sme, &swsensor_edata, 227 &sw_sensor_deflims, &sw_sensor_defprops); 228 } 229 230 /* See if an initial value was specified */ 231 if (pd != NULL) 232 po = prop_dictionary_get(pd, "value"); 233 234 if (po != NULL && prop_object_type(po) == PROP_TYPE_NUMBER) 235 sw_sensor_value = prop_number_integer_value(po); 236 237 swsensor_edata.value_cur = 0; 238 239 strlcpy(swsensor_edata.desc, "sensor", ENVSYS_DESCLEN); 240 241 error = sysmon_envsys_sensor_attach(swsensor_sme, &swsensor_edata); 242 243 if (error == 0) 244 error = sysmon_envsys_register(swsensor_sme); 245 else { 246 aprint_error("sysmon_envsys_sensor_attach failed: %d\n", error); 247 return error; 248 } 249 250 if (error == 0) 251 sysctl_swsensor_setup(); 252 else 253 aprint_error("sysmon_envsys_register failed: %d\n", error); 254 255 if (error == 0) 256 aprint_normal("swsensor: initialized\n"); 257 return error; 258 } 259 260 static 261 int 262 swsensor_fini(void *arg) 263 { 264 265 sysmon_envsys_unregister(swsensor_sme); 266 267 sysctl_teardown(&swsensor_sysctllog); 268 269 return 0; 270 } 271 272 static 273 int 274 swsensor_modcmd(modcmd_t cmd, void *arg) 275 { 276 int ret; 277 278 switch (cmd) { 279 case MODULE_CMD_INIT: 280 ret = swsensor_init(arg); 281 break; 282 283 case MODULE_CMD_FINI: 284 ret = swsensor_fini(arg); 285 break; 286 287 case MODULE_CMD_STAT: 288 default: 289 ret = ENOTTY; 290 } 291 292 return ret; 293 } 294 295 int 296 swsensorattach(int n __unused) 297 { 298 299 #ifdef MODULAR 300 /* 301 * Modular kernels will automatically load any built-in modules 302 * and call their modcmd() routine, so we don't need to do it 303 * again as part of pseudo-device configuration. 304 */ 305 return 0; 306 #else 307 return swsensor_init(NULL); 308 #endif 309 } 310