KSENSOR_OPS(9E) Driver Entry Points KSENSOR_OPS(9E)

NAME


ksensor_ops, kso_kind, kso_scalar - ksensor entry points

SYNOPSIS


#include <sys/sensors.h>

int
kso_kind(void *driver, sensor_ioctl_kind_t *kind);

int
kso_scalar(void *driver, sensor_ioctl_scalar_t *scalar);

INTERFACE LEVEL


Volatile - This interface is still evolving in illumos. API and ABI
stability is not guaranteed.

PARAMETERS


driver A pointer to the driver's private data that was passed as an
argument to ksensor_create(9F).

kind A pointer to a structure the driver will fill out to answer
what kind of sensor it is.

scalar A pointer to a structure that the driver will fill out to
answer the current value of the sensor.

DESCRIPTION


The ksensor(9E) framework requires that device drivers provide an
operations vector when registering a sensor with ksensor_create(9F). The
operations vector uses the ksensor_ops_t structure and is implemented in
terms of two entry points kso_kind() and kso_scalar(), both of which are
required.

In all entry points, the driver will be passed back driver, which is the
argument registered when the sensor was created. This provides the driver
a direct means to determine which sensor the framework is asking about and
allows the same operations vector to serve multiple instances of a sensor.

The ksensor framework does not serialize calls to the operations vectors as
part of its contract to sensor providers. Drivers must assume that the
various entry points will be called in parallel from multiple threads and
that if any locking is required, it is the driver's responsibility.

ksensor kind
The kso_kind() entry point is used to answer the question of what kind of
sensor something is. A ksensor's kind indicates to the user what type of
physical phenomenon the sensor manages such as temperature, voltage, etc.
Some sensors are synthesized from physical phenomena, but don't represent
one themselves. These sensors use the kso_kind() entry point to indicate
that and what they're derived from. For many drivers, they can use one of
the stock implementations that the kernel provides such as
ksensor_kind_temperature(9F), ksensor_kind_voltage(9F), or
ksensor_kind_current(9F) if they're a stock temperature, voltage, or
current sensor.

For drivers that must implement this themselves, they should fill out the
members of the sensor_ioctl_kind_t structure as follows:

sik_kind This member should be filled in with the kind of the sensor
from the list in ksensor(9E). The driver should not use
SENSOR_KIND_UNKNOWN. If the driver uses
SENSOR_KIND_SYNTHETIC then it should fill in sik_derive.

sik_derive If the driver did not set sik_kind to SENSOR_KIND_SYNTHETIC,
then this member should not be set and left at its default
value that the framework provides. Otherwise, if the type
that it is derived from is known, then it should be set to
one of the kind values other than SENSOR_KIND_UNKNOWN and
SENSOR_KIND_SYNTHETIC.

ksensor scalar
The kso_scalar() entry point is used to return information about a scalar
value read from a sensor. This is the primary interface by which a value
is read from a device. For more information on scalar sensors and the
intended semantics, see the Sensor Types, Kinds, Units, and Naming section
of ksensor(9E).

When this entry point is called, the driver should fill out the members of
the sensor_ioctl_scalar_t structure as follows:

sis_unit A uint32_t that indicates the unit that the sensor is in.
This should be one of the units from the list in ksensor(9E)
and should not be SENSOR_UNIT_UNKNOWN. SENSOR_UNIT_NONE
should only be used if the sensor's kind is
SENSOR_KIND_SYNTHETIC.

sis_gran An int32_t that indicates the granularity or resolution of
the sensor. The granularity indicates the number of
increments per unit in the measurement. A value such as 10
indicates that the value is in 10ths of the unit. If this
was a temperature sensor, one would need to divide sit_value
by 10 to obtain degrees. On the other hand a negative
granularity indicates one would need to multiply sit_value to
get the actual base unit. For example, a value of -2 would
indicate that actual number of degrees, you'd need to
multiply the value by two.

sis_prec A uint32_t that represents the accuracy of the sensor itself
and is measured in units of the granularity. For example, a
temperature sensor that has a granularity of 1, meaning the
value read from the sensor is in degrees, and is accurate to
+/-5 degrees would set the precision to 5. Conversely, a
temperature sensor that measured in 0.5 degree increments has
a granularity of 2. If the sensor was accurate to +/-1
degree, then it'd have a precision of 2. If the precision is
unknown, it should be left at zero.

sis_value A int64_t that represents the value read from the sensor. It
is in units of the granularity and is a signed quantity.

CONTEXT


The kso_kind() and kso_scalar() functions are generally called from kernel
context. While these functions may be called from user context, the driver
must not assume that and should not be copying any data into or out of a
user process.

RETURN VALUES


Upon successful completion, the device driver should have filled out the
corresponding structure into kind or scalar and return 0. Otherwise, a
positive error number should be returned to indicate the failure.

EXAMPLES


Example 1 Example PCI-based Implementation

The following example shows what this might look like for PCI-based device
driver that has a temperature sensor in configure space. This example
assumes the sensor measures in 0.5 degree increments and is accurate to
+/-1 degree .

#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sensors.h>

/*
* Our temperature sensor in configuration space. It returns an unsigned
* 32-bit value in 0.5 degree increments that indicates the current
* temperature in degrees C.
*/
#define EX_SENSOR 0x200

/*
* Our granularity is 0.5 degrees. Our precision is +/-1 degree, which
* is 2 units of our granularity, hence we define it as 2.
*/
#define EX_SENSOR_GRAN 2
#define EX_SENSOR_PREC 2

/*
* Driver structure that is registered with ksensor_create(9F). The
* ex_cfg member comes from a call to pci_config_setup() during
* attach(9E).
*/
typedef struct ex {
...
ddi_acc_handle_t ex_cfg;
...
} ex_t;

static int
ex_sensor_temp_read(void *arg, sensor_ioctl_scalar_t *scalar)
{
uint32_t reg;
ex_t *ex = arg;

reg = pci_config_get32(ex->ex_cfg, EX_SENSOR);
scalar->sis_unit = SENSOR_UNIT_CELSIUS;
scalar->sis_gran = EX_SENSOR_GRAN;
scalar->sis_prec = EX_SENSOR_PREC;
scalar->sis_value = reg;
return (0);
}

static const ksensor_ops_t ex_sensor_temp_ops = {
.kso_kind = ksensor_kind_temperature,
.kso_scalar = ex_sensor_temp_read
};

ERRORS


The device driver may return one of the following errors, but is not
limited to this set if there is a more accurate error based on the
situation.

EIO This error should be used when the driver fails to
communicate with the device to read the current sensor
value.

SEE ALSO


ksensor(9E), ksensor_create(9F), ksensor_kind(9F)

illumos May 10, 2024 illumos