Home | History | Annotate | Line # | Download | only in sysmon
swsensor.c revision 1.7.6.2
      1 /*	$NetBSD: swsensor.c,v 1.7.6.2 2011/03/05 20:54:08 rmind 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.6.2 2011/03/05 20:54:08 rmind 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