main: Add HWMon light sensor support
As used on Mac laptops. Note that some devices have multiple sensors. As advised in Microsoft documentation, we will only use the values from the sensor with the highest value, to avoid problems with potentially obscured sensors. Tested on MacBookPro8,2
This commit is contained in:
@@ -9,7 +9,8 @@ iio_sensor_proxy_SOURCES = \
|
|||||||
drv-iio-poll-accel.c \
|
drv-iio-poll-accel.c \
|
||||||
drv-input-accel.c \
|
drv-input-accel.c \
|
||||||
drv-fake-light.c \
|
drv-fake-light.c \
|
||||||
drv-iio-poll-light.c
|
drv-iio-poll-light.c \
|
||||||
|
drv-hwmon-light.c
|
||||||
|
|
||||||
iio_sensor_proxy_CPPFLAGS = \
|
iio_sensor_proxy_CPPFLAGS = \
|
||||||
$(IIO_SENSOR_PROXY_CFLAGS) \
|
$(IIO_SENSOR_PROXY_CFLAGS) \
|
||||||
|
@@ -24,7 +24,8 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DRIVER_TYPE_LIGHT_IIO,
|
DRIVER_TYPE_LIGHT_IIO,
|
||||||
DRIVER_TYPE_LIGHT_FAKE
|
DRIVER_TYPE_LIGHT_FAKE,
|
||||||
|
DRIVER_TYPE_LIGHT_HWMON
|
||||||
} DriverLightType;
|
} DriverLightType;
|
||||||
|
|
||||||
typedef struct SensorDriver SensorDriver;
|
typedef struct SensorDriver SensorDriver;
|
||||||
@@ -61,3 +62,4 @@ extern SensorDriver iio_poll_accel;
|
|||||||
extern SensorDriver input_accel;
|
extern SensorDriver input_accel;
|
||||||
extern SensorDriver fake_light;
|
extern SensorDriver fake_light;
|
||||||
extern SensorDriver iio_poll_light;
|
extern SensorDriver iio_poll_light;
|
||||||
|
extern SensorDriver hwmon_light;
|
||||||
|
122
src/drv-hwmon-light.c
Normal file
122
src/drv-hwmon-light.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Bastien Nocera <hadess@hadess.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DEFAULT_POLL_TIME 8000
|
||||||
|
#define MAX_LIGHT_LEVEL 255
|
||||||
|
|
||||||
|
typedef struct DrvData {
|
||||||
|
ReadingsUpdateFunc callback_func;
|
||||||
|
gpointer user_data;
|
||||||
|
|
||||||
|
char *light_path;
|
||||||
|
guint timeout_id;
|
||||||
|
} DrvData;
|
||||||
|
|
||||||
|
static DrvData *drv_data = NULL;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hwmon_light_discover (GUdevDevice *device)
|
||||||
|
{
|
||||||
|
char *light_path;
|
||||||
|
|
||||||
|
if (g_strcmp0 (g_udev_device_get_subsystem (device), "platform") != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (g_strcmp0 (g_udev_device_get_property (device, "MODALIAS"), "platform:applesmc") != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
light_path = g_build_filename (g_udev_device_get_sysfs_path (device),
|
||||||
|
"light", NULL);
|
||||||
|
if (!g_file_test (light_path, G_FILE_TEST_EXISTS)) {
|
||||||
|
g_free (light_path);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
g_free (light_path);
|
||||||
|
|
||||||
|
g_debug ("Found HWMon light at %s", g_udev_device_get_sysfs_path (device));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
light_changed (void)
|
||||||
|
{
|
||||||
|
LightReadings readings;
|
||||||
|
gdouble level;
|
||||||
|
char *contents;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (g_file_get_contents (drv_data->light_path, &contents, NULL, &error)) {
|
||||||
|
int light1, light2;
|
||||||
|
if (sscanf (contents, "(%d,%d)", &light1, &light2) != 2) {
|
||||||
|
g_warning ("Failed to parse light level: %s", contents);
|
||||||
|
g_free (contents);
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
level = ((float) MAX(light1, light2)) / (float) MAX_LIGHT_LEVEL * 100.0;
|
||||||
|
g_free (contents);
|
||||||
|
} else {
|
||||||
|
g_warning ("Failed to read input level at %s: %s",
|
||||||
|
drv_data->light_path, error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
readings.level = level;
|
||||||
|
readings.uses_lux = FALSE;
|
||||||
|
drv_data->callback_func (&hwmon_light, (gpointer) &readings, drv_data->user_data);
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hwmon_light_open (GUdevDevice *device,
|
||||||
|
ReadingsUpdateFunc callback_func,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
drv_data = g_new0 (DrvData, 1);
|
||||||
|
drv_data->callback_func = callback_func;
|
||||||
|
drv_data->user_data = user_data;
|
||||||
|
|
||||||
|
drv_data->light_path = g_build_filename (g_udev_device_get_sysfs_path (device),
|
||||||
|
"light", NULL);
|
||||||
|
|
||||||
|
drv_data->timeout_id = g_timeout_add (DEFAULT_POLL_TIME,
|
||||||
|
(GSourceFunc) light_changed,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hwmon_light_close (void)
|
||||||
|
{
|
||||||
|
if (drv_data->timeout_id != 0) {
|
||||||
|
g_source_remove (drv_data->timeout_id);
|
||||||
|
drv_data->timeout_id = 0;
|
||||||
|
}
|
||||||
|
g_clear_pointer (&drv_data->light_path, g_free);
|
||||||
|
g_clear_pointer (&drv_data, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorDriver hwmon_light = {
|
||||||
|
.name = "Platform HWMon Light",
|
||||||
|
.type = DRIVER_TYPE_LIGHT,
|
||||||
|
.specific_type = DRIVER_TYPE_LIGHT_HWMON,
|
||||||
|
|
||||||
|
.discover = hwmon_light_discover,
|
||||||
|
.open = hwmon_light_open,
|
||||||
|
.close = hwmon_light_close,
|
||||||
|
};
|
@@ -86,6 +86,7 @@ static const SensorDriver * const drivers[] = {
|
|||||||
&iio_poll_accel,
|
&iio_poll_accel,
|
||||||
&input_accel,
|
&input_accel,
|
||||||
&iio_poll_light,
|
&iio_poll_light,
|
||||||
|
&hwmon_light,
|
||||||
&fake_light
|
&fake_light
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,12 +107,14 @@ static gboolean
|
|||||||
find_sensors (GUdevClient *client,
|
find_sensors (GUdevClient *client,
|
||||||
SensorData *data)
|
SensorData *data)
|
||||||
{
|
{
|
||||||
GList *devices, *input, *l;
|
GList *devices, *input, *platform, *l;
|
||||||
gboolean found = FALSE;
|
gboolean found = FALSE;
|
||||||
|
|
||||||
devices = g_udev_client_query_by_subsystem (client, "iio");
|
devices = g_udev_client_query_by_subsystem (client, "iio");
|
||||||
input = g_udev_client_query_by_subsystem (client, "input");
|
input = g_udev_client_query_by_subsystem (client, "input");
|
||||||
|
platform = g_udev_client_query_by_subsystem (client, "platform");
|
||||||
devices = g_list_concat (devices, input);
|
devices = g_list_concat (devices, input);
|
||||||
|
devices = g_list_concat (devices, platform);
|
||||||
|
|
||||||
/* Find the devices */
|
/* Find the devices */
|
||||||
for (l = devices; l != NULL; l = l->next) {
|
for (l = devices; l != NULL; l = l->next) {
|
||||||
@@ -420,7 +423,7 @@ int main (int argc, char **argv)
|
|||||||
SensorData *data;
|
SensorData *data;
|
||||||
GUdevClient *client;
|
GUdevClient *client;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const gchar * const subsystems[] = { "iio", "input", NULL };
|
const gchar * const subsystems[] = { "iio", "input", "platform", NULL };
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
/* g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); */
|
/* g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); */
|
||||||
|
Reference in New Issue
Block a user