#define MAX_DEVICES 9 /* Check iio devices 0 to MAX_DEVICES-1 */
#define MAX_SENSORS 11 /* We can handle as many sensors */
#define MAX_CHANNELS 4 /* We can handle as many channels per sensor */
+#define MAX_EVENTS 8 /* We can handle as many events per channel */
#define MAX_TRIGGERS 8 /* Check for triggers 0 to MAX_TRIGGERS-1 */
#define DEV_FILE_PATH "/dev/iio:device%d"
#define ENABLE_PATH BASE_PATH "buffer/enable"
#define NAME_PATH BASE_PATH "name"
#define TRIGGER_PATH BASE_PATH "trigger/current_trigger"
+#define EVENTS_PATH BASE_PATH "events/"
#define SENSOR_ENABLE_PATH BASE_PATH "in_%s_en"
#define SENSOR_OFFSET_PATH BASE_PATH "in_%s_offset"
#define SENSOR_SCALE_PATH BASE_PATH "in_%s_scale"
#define MODE_AUTO 0 /* autodetect */
#define MODE_POLL 1
#define MODE_TRIGGER 2
+#define MODE_EVENT 3
+
+typedef struct
+{
+ const char *type; /* event type; e.g: transition */
+ const char *dir; /* event direction; e.g: rising */
+
+ /* sysfs entries located in /sys/bus/iio/devices/iio:deviceX/events/ */
+ const char *ev_en_path;
+ const char *ev_value_path;
+}
+event_descriptor_t;
+
typedef struct
{
const char *raw_path; /* _raw sysfs file name */
const char *input_path; /* _input sysfs file name */
const char *scale_path; /* _scale sysfs file name */
+
+ const int num_events;
+ event_descriptor_t event[MAX_EVENTS];
}
channel_descriptor_t;
#include <time.h>
#include <math.h>
#include <sys/epoll.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <utils/Log.h>
#include <hardware/sensors.h>
+#include <linux/iio/events.h>
#include "control.h"
#include "enumeration.h"
#include "utils.h"
static int trig_sensors_per_dev[MAX_DEVICES]; /* trigger, event based */
static int device_fd[MAX_DEVICES]; /* fd on the /dev/iio:deviceX file */
+static int events_fd[MAX_DEVICES]; /* fd on the /sys/bus/iio/devices/iio:deviceX/events/<event_name> file */
static int has_iio_ts[MAX_DEVICES]; /* ts channel available on this iio dev */
static int expected_dev_report_size[MAX_DEVICES]; /* expected iio scan len */
static int poll_fd; /* epoll instance covering all enabled sensors */
return ret;
}
+static int enable_event(int dev_num, const char *name, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, EVENTS_PATH "%s", dev_num, name);
+ return sysfs_write_int(sysfs_path, enabled);
+}
static int enable_sensor(int dev_num, const char *tag, int enabled)
{
poll_sensors_per_dev[dev_num]--;
return 1;
}
+ case MODE_EVENT:
+ return 1;
default:
/* Invalid sensor mode */
return -1;
{
char device_name[PATH_MAX];
struct epoll_event ev = {0};
- int dev_fd;
- int ret;
+ int dev_fd, event_fd;
+ int ret, c, d;
int dev_num = sensor[s].dev_num;
size_t field_size;
int catalog_index = sensor[s].catalog_index;
device_fd[dev_num] = -1;
}
+ if (sensor[s].mode == MODE_EVENT) {
+ event_fd = events_fd[dev_num];
+
+ for (c = 0; c < sensor_catalog[catalog_index].num_channels; c++) {
+ for (d = 0; d < sensor_catalog[catalog_index].channel[c].num_events; d++)
+ enable_event(dev_num, sensor_catalog[catalog_index].channel[c].event[d].ev_en_path, enabled);
+ }
+
+ epoll_ctl(poll_fd, EPOLL_CTL_DEL, event_fd, NULL);
+ close(event_fd);
+ events_fd[dev_num] = -1;
+
+ }
+
/* Release any filtering data we may have accumulated */
release_noise_filtering_data(s);
}
/* Note: poll-mode fds are not readable */
+ } else if (sensor[s].mode == MODE_EVENT) {
+ event_fd = events_fd[dev_num];
+
+ ret = ioctl(dev_fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
+ if (ret == -1 || event_fd == -1) {
+ ALOGE("Failed to retrieve event_fd from %d (%s)\n", dev_fd, strerror(errno));
+ return -1;
+ }
+ events_fd[dev_num] = event_fd;
+ ALOGV("Opened fd=%d to receive events\n", event_fd);
+
+ /* Add this event fd to the set of watched fds */
+ ev.events = EPOLLIN;
+ ev.data.u32 = dev_num;
+
+ ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, event_fd, &ev);
+ if (ret == -1) {
+ ALOGE("Failed adding %d to poll set (%s)\n", event_fd, strerror(errno));
+ return -1;
+ }
+ for (c = 0; c < sensor_catalog[catalog_index].num_channels; c++) {
+ int d;
+ for (d = 0; d < sensor_catalog[catalog_index].channel[c].num_events; d++)
+ enable_event(dev_num, sensor_catalog[catalog_index].channel[c].event[d].ev_en_path, enabled);
+ }
+
+ if (!poll_sensors_per_dev[dev_num] && !trig_sensors_per_dev[dev_num]) {
+ close(dev_fd);
+ device_fd[dev_num] = -1;
+ }
}
}
}
-static int integrate_device_report (int dev_num)
+static int integrate_device_report_from_dev(int dev_num, int fd)
{
int len;
int s,c;
int64_t boot_to_rt_delta;
/* There's an incoming report on the specified iio device char dev fd */
-
- if (dev_num < 0 || dev_num >= MAX_DEVICES) {
- ALOGE("Event reported on unexpected iio device %d\n", dev_num);
- return -1;
- }
-
- if (device_fd[dev_num] == -1) {
+ if (fd == -1) {
ALOGE("Ignoring stale report on iio device %d\n", dev_num);
return -1;
}
- len = read(device_fd[dev_num], buf, expected_dev_report_size[dev_num]);
+ len = read(fd, buf, expected_dev_report_size[dev_num]);
if (len == -1) {
ALOGE("Could not read report from iio device %d (%s)\n", dev_num, strerror(errno));
return 0;
}
+static int integrate_device_report_from_event(int dev_num, int fd)
+{
+ int len, s;
+ int64_t ts;
+ struct iio_event_data event;
+
+ /* There's an incoming report on the specified iio device char dev fd */
+ if (fd == -1) {
+ ALOGE("Ignoring stale report on event fd %d of device %d\n",
+ fd, dev_num);
+ return -1;
+ }
+
+ len = read(fd, &event, sizeof(event));
+
+ if (len == -1) {
+ ALOGE("Could not read event from fd %d of device %d (%s)\n",
+ fd, dev_num, strerror(errno));
+ return -1;
+ }
+
+ ts = event.timestamp;
+
+ ALOGV("Read event %ld from fd %d of iio device %d\n", event.id, fd, dev_num);
+
+ /* Map device report to sensor reports */
+ for (s = 0; s < MAX_SENSORS; s++)
+ if (sensor[s].dev_num == dev_num &&
+ is_enabled(s)) {
+ sensor[s].report_ts = ts;
+ sensor[s].report_pending = 1;
+ sensor[s].report_initialized = 1;
+ ALOGV("Sensor %d report available (1 byte)\n", s);
+ }
+ return 0;
+}
+
+static int integrate_device_report(int dev_num)
+{
+ int ret = 0;
+
+ if (dev_num < 0 || dev_num >= MAX_DEVICES) {
+ ALOGE("Event reported on unexpected iio device %d\n", dev_num);
+ return -1;
+ }
+
+ if (events_fd[dev_num] != -1) {
+ ret = integrate_device_report_from_event(dev_num, events_fd[dev_num]);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (device_fd[dev_num] != -1)
+ ret = integrate_device_report_from_dev(dev_num, device_fd[dev_num]);
+
+ return ret;
+}
static int propagate_vsensor_report (int s, sensors_event_t *data)
{
data->type = sensor[s].type;
data->timestamp = sensor[s].report_ts;
+ if (sensor[s].mode == MODE_EVENT) {
+ ALOGV("Reporting event\n");
+ /* Android requires events to return 1.0 */
+ data->data[0] = 1.0;
+ data->data[1] = 0.0;
+ data->data[2] = 0.0;
+ return 1;
+ }
+
/* Convert the data into the expected Android-level format */
current_sample = sensor[s].report_buffer;
{
int i;
- for (i=0; i<MAX_DEVICES; i++)
+ for (i=0; i<MAX_DEVICES; i++) {
device_fd[i] = -1;
+ events_fd[i] = -1;
+ }
poll_fd = epoll_create(MAX_DEVICES);
}
}
+static void check_event_sensors(int i, char *sysfs_file, char map[CATALOG_SIZE])
+{
+ int j, k;
+
+ for (j = 0; j < sensor_catalog[i].num_channels; j++)
+ for (k = 0; k < sensor_catalog[i].channel[j].num_events; k++)
+ if (!strcmp(sysfs_file, sensor_catalog[i].channel[j].event[k].ev_en_path)) {
+ map[i] = 1;
+ return ;
+ }
+}
+
static void virtual_sensors_check (void)
{
int i;
*/
char poll_sensors[CATALOG_SIZE];
char trig_sensors[CATALOG_SIZE];
+ char event_sensors[CATALOG_SIZE];
int dev_num;
unsigned int i;
int trig_found;
discover_sensors(dev_num, BASE_PATH, poll_sensors, check_poll_sensors);
discover_sensors(dev_num, CHANNEL_PATH, trig_sensors, check_trig_sensors);
+ discover_sensors(dev_num, EVENTS_PATH, event_sensors, check_event_sensors);
- for (i=0; i<CATALOG_SIZE; i++)
+ for (i=0; i<CATALOG_SIZE; i++) {
+ if (event_sensors[i]) {
+ add_sensor(dev_num, i, MODE_EVENT);
+ continue;
+ }
if (trig_sensors[i]) {
add_sensor(dev_num, i, MODE_TRIGGER);
trig_found = 1;
+ continue;
}
- else
- if (poll_sensors[i])
- add_sensor(dev_num, i, MODE_POLL);
+ if (poll_sensors[i]) {
+ add_sensor(dev_num, i, MODE_POLL);
+ continue;
+ }
+ }
if (trig_found)
build_sensor_report_maps(dev_num);
* hardware/libhardware/include/hardware/sensor.h
*/
+#define DECLARE_VOID_CHANNEL(tag) \
+ tag, \
+ "", \
+ "", \
+ "", \
+ "", \
+ "", \
+ "", \
+
#define DECLARE_CHANNEL(tag, spacer, name) \
name, \
"in_"tag spacer name"_en", \
#define DECLARE_GENERIC_CHANNEL(tag) DECLARE_CHANNEL(tag, "", "")
+#define DECLARE_EVENT(tag, spacer1, name, spacer2, type, spacer3, dir) \
+ type, dir, \
+ "in_"tag spacer1 name spacer2 type spacer3 dir"_en", \
+ "in_"tag spacer1 name spacer2 type spacer3 dir"_value", \
+
+#define DECLARE_GENERIC_EVENT(tag, name, type, dir) \
+ DECLARE_EVENT(tag, "_", name, "_", type, "_", dir)
+#define DECLARE_NAMED_EVENT(tag, name) \
+ DECLARE_EVENT(tag, "_", name, "","","","")
+
int get_sensors_list (struct sensors_module_t* module,
struct sensor_t const** list);