struct
sysmon_envsys
*
sysmon_envsys_create(
void
)
void
sysmon_envsys_destroy(
struct sysmon_envsys *
)
int
sysmon_envsys_register(
struct sysmon_envsys *
)
void
sysmon_envsys_unregister(
struct sysmon_envsys *
)
int
sysmon_envsys_sensor_attach(
struct sysmon_envsys *, envsys_data_t *
)
int
sysmon_envsys_sensor_detach(
struct sysmon_envsys *, envsys_data_t *
)
sysmon_envsys is the kernel part of the envsys(4) framework. With this framework you are able to register and unregister a sysmon_envsys device, attach or detach sensors into a device and enable or disable automatic monitoring for some sensors without any user interactivity, among other things.
To register a new driver to the
sysmon_envsys
framework, a
sysmon_envsys
object must be allocated and initialized; the
sysmon_envsys_create()
function is used for this. This returns a zero'ed pointer to a sysmon_envsys
structure and takes care of initialization of some private features.
Once we have the object we could start initializing sensors (see the
SENSOR DETAILS
section for more information) and attaching
them to the device, this is acomplished by the
sysmon_envsys_sensor_attach()
function. This function attachs the envsys_data_t (sensor) specified
as second argument into the sysmon_envsys object specified in the
first argument.
Finally when the sensors are already attached, the device needs to set
some required (and optional) members of the sysmon_envsys struct before
calling the
sysmon_envsys_register()
function to register the device.
If there's some error before registering the device, the
sysmon_envsys_destroy()
function must be used to detach the sensors previously attached
and free the sysmon_envsys object allocated by the
sysmon_envsys_create(
)
function.
The
sysmon_envsys
structure is defined as follow
(only the public members are shown):
struct sysmon_envsys {
const char *sme_name;
int sme_flags;
int sme_class;
uint64_t sme_events_timeout;
void *sme_cookie;
void (*sme_refresh)(struct sysmon_envsys *, envsys_data_t *);
};
The members have the following meaning:
sme_class
sme_name
sme_flags
sme_events_timeout
If the driver wants to refresh sensors data via the sysmon_envsys framework, the following members must be specified:
sme_cookie
sme_refresh
Note that it's not necessary to refresh the sensors data before the driver is registered, only do it if you need the data in your driver to check for a specific condition.
The timeout value for the monitoring events on a device may be changed via the ENVSYS_SETDICTIONARY ioctl(2) or the envstat(8) command.
To unregister a driver previously registered with the
sysmon_envsys
framework, the
sysmon_envsys_unregister()
function must be used. If there were monitoring events registered for the
driver, they all will be destroyed before the device is unregistered and
its sensors will be detached; finally the
sysmon_envsys
object will be freed, so there's no need to call
sysmon_envsys_destroy(
)
if we are going to unregister a device.
sme_class
member of the
sysmon_envsys
structure is an optional flag that specifies the class of the
sysmon envsys device. Currently there are two classes:
This class is for devices that want to act as an AC adapter. The device writer must ensure that at least there is a sensor with units of ENVSYS_INDICATOR. This will be used to report its current state (on/off).
This class is for devices that want to act as an Battery. The device writer must ensure that at least there are two sensors with units of ENVSYS_BATTERY_CAPACITY and ENVSYS_BATTERY_CHARGE.
These two sensors are used to ensure that the battery device won't
never send a
low-power
event to the
powerd(8)
daemon (if running) when all battery devices are in a critical state.
The critical state means that a battery is not currently charging
and its charge state is low or critical.
When the
low-power
condition is met, an event is sent to the
powerd(8)
daemon (if running) and will shutdown the system gracefully via the
/etc/powerd/scripts/sensor_battery
script.
If powerd(8) is not running, the system will be powered off via the cpu_reboot(9) call with the RB_POWERDOWN flag.
Each sensor uses a
envsys_data_t
structure, it's defined as follow (only the public members are shown);
typedef struct envsys_data {
uint32_t units;
uint32_t state;
uint32_t flags;
uint32_t rpms;
int32_t rfact;
int32_t value_cur;
int32_t value_max;
int32_t value_min;
int32_t value_avg;
bool monitor;
char desc[ENVSYS_DESCLEN];
} envsys_data_t;
The members for the envsys_data_t structure have the following meaning:
units
state
flags
rpms
rfact
value_cur
value_max
value_min
value_avg
monitor
desc
Users of this framework must take care about the following points:
ioctl(2)
This flag has not any effect for monitoring flags set in the driver and it's
only meant to disable setting critical limits from userland.
If the driver has to use any of the value_max, value_min or value_avg members, they should be marked as valid with the appropiate flag.
The following types shouldn't need any conversion: ENVSYS_BATTERY_CAPACITY, ENVSYS_BATTERY_CHARGE, ENVSYS_INDICATOR, ENVSYS_INTEGER and ENVSYS_DRIVE.
PLEASE NOTE THAT YOU MUST AVOID USING FLOATING POINT OPERATIONS IN KERNEL WHEN CONVERTING THE DATA RETURNED BY THE DRIVER TO THE APPROPIATE UNIT, IT'S NOT ALLOWED.
/*
* the monitor member must be true to enable
* automatic monitoring.
*/
sc->sc_sensor[0].monitor = true;
/* and now we specify the type of the monitoring event */
sc->sc_sensor[0].flags |= ENVSYS_FMONCRITICAL;
...
}
int
mydriver_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct mysoftc *sc = sme->sme_cookie;
/* we get current data from the driver */
edata->value_cur = sc->sc_getdata();
/*
* if value is too high, mark the sensor in
* critical state.
*/
if (edata->value_cur > MYDRIVER_SENSOR0_HIWAT) {
edata->state = ENVSYS_SCRITICAL;
/* a critical event will be sent now automatically */
} else {
/*
* if value is within the limits, and we came from
* a critical state make sure to change sensor's state
* to valid.
*/
edata->state = ENVSYS_SVALID;
}
...
}
int
mydriver_initialize_sensors(struct mysoftc *sc)
{
...
/* sensor is initialized with a valid state */
sc->sc_sensor[0].state = ENVSYS_SVALID;
/usr/src
.
The envsys 2 framework is implemented within the files:
sys/dev/sysmon/sysmon_envsys.c
sys/dev/sysmon/sysmon_envsys_events.c
sys/dev/sysmon/sysmon_envsys_tables.c
sys/dev/sysmon/sysmon_envsys_util.c
There's an example LKM driver that shows how the framework works in:
sys/lkm/misc/envsys2/lkminit_envsys2.c
.
The first envsys framework was implemented by Jason R. Thorpe, Tim Rightnour and Bill Squier.