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:
Bastien Nocera
2015-03-19 16:05:11 +01:00
parent dba141da81
commit ea46714d91
4 changed files with 132 additions and 4 deletions

View File

@@ -9,7 +9,8 @@ iio_sensor_proxy_SOURCES = \
drv-iio-poll-accel.c \
drv-input-accel.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_CFLAGS) \

View File

@@ -24,7 +24,8 @@ typedef enum {
typedef enum {
DRIVER_TYPE_LIGHT_IIO,
DRIVER_TYPE_LIGHT_FAKE
DRIVER_TYPE_LIGHT_FAKE,
DRIVER_TYPE_LIGHT_HWMON
} DriverLightType;
typedef struct SensorDriver SensorDriver;
@@ -61,3 +62,4 @@ extern SensorDriver iio_poll_accel;
extern SensorDriver input_accel;
extern SensorDriver fake_light;
extern SensorDriver iio_poll_light;
extern SensorDriver hwmon_light;

122
src/drv-hwmon-light.c Normal file
View 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,
};

View File

@@ -86,6 +86,7 @@ static const SensorDriver * const drivers[] = {
&iio_poll_accel,
&input_accel,
&iio_poll_light,
&hwmon_light,
&fake_light
};
@@ -106,12 +107,14 @@ static gboolean
find_sensors (GUdevClient *client,
SensorData *data)
{
GList *devices, *input, *l;
GList *devices, *input, *platform, *l;
gboolean found = FALSE;
devices = g_udev_client_query_by_subsystem (client, "iio");
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, platform);
/* Find the devices */
for (l = devices; l != NULL; l = l->next) {
@@ -420,7 +423,7 @@ int main (int argc, char **argv)
SensorData *data;
GUdevClient *client;
int ret = 0;
const gchar * const subsystems[] = { "iio", "input", NULL };
const gchar * const subsystems[] = { "iio", "input", "platform", NULL };
guint i;
/* g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); */