1 /*
2 * Copyright (C) 2008-2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <ctype.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <math.h>
23 #include <poll.h>
24 #include <pthread.h>
25 #include <stdlib.h>
26 #include <sys/select.h>
27 #include <unistd.h>
28
29 #define LOG_TAG "CrosECSensor"
30 #include <cutils/log.h>
31 #include <cutils/properties.h>
32 #include <utils/Timers.h>
33
34 #include "cros_ec_sensors.h"
35
36
37 /*****************************************************************************/
max(int a,int b)38 static int max(int a, int b) {
39 return (a > b) ? a : b;
40 }
min(int a,int b)41 static int min(int a, int b) {
42 return (a < b) ? a : b;
43 }
44
45 /*
46 * Constructor.
47 *
48 * Setup and open the ring buffer.
49 */
CrosECSensor(struct cros_ec_sensor_info * sensor_info,size_t sensor_nb,struct cros_ec_gesture_info * gesture_info,size_t gesture_nb,const char * ring_device_name,const char * trigger_name)50 CrosECSensor::CrosECSensor(
51 struct cros_ec_sensor_info *sensor_info,
52 size_t sensor_nb,
53 struct cros_ec_gesture_info *gesture_info,
54 size_t gesture_nb,
55 const char *ring_device_name,
56 const char *trigger_name)
57 : mSensorInfo(sensor_info),
58 mSensorNb(sensor_nb),
59 mGestureInfo(gesture_info),
60 mGestureNb(gesture_nb)
61 {
62 char ring_buffer_name[IIO_MAX_NAME_LENGTH] = "/dev/";
63
64 strcat(ring_buffer_name, ring_device_name);
65 mDataFd = open(ring_buffer_name, O_RDONLY);
66 if (mDataFd < 0) {
67 ALOGE("open file '%s' failed: %s\n",
68 ring_buffer_name, strerror(errno));
69 }
70
71 strcpy(mRingPath, ring_device_name);
72
73 /* Be sure the buffer is disbabled before altering parameters */
74 if (cros_ec_sysfs_set_input_attr_by_int(mRingPath, "buffer/enable", 0) < 0) {
75 ALOGE("disable IIO buffer failed: %s\n", strerror(errno));
76 return;
77 }
78 if (cros_ec_sysfs_set_input_attr(mRingPath, "trigger/current_trigger",
79 trigger_name, strlen(trigger_name))) {
80 ALOGE("Unable to set trigger name: %s\n", strerror(errno));
81 return;
82 }
83 if (cros_ec_sysfs_set_input_attr_by_int(mRingPath, "buffer/length",
84 IIO_MAX_BUFF_SIZE) < 0) {
85 ALOGE("set IIO buffer length (%d) failed: %s\n",
86 IIO_MAX_BUFF_SIZE, strerror(errno));
87 }
88 if (cros_ec_sysfs_set_input_attr_by_int(mRingPath, "buffer/enable", 1) < 0) {
89 ALOGE("enable IIO buffer failed: %s\n",
90 strerror(errno));
91 return;
92 }
93 }
94
~CrosECSensor()95 CrosECSensor::~CrosECSensor() {
96 /* Silence all the sensors, so that we can stop the buffer */
97 for (size_t i = 0 ; i < mSensorNb ; i++) {
98 if (mSensorInfo[i].device_name == NULL)
99 continue;
100 activate(i, 0);
101 }
102 for (size_t i = 0 ; i < mGestureNb ; i++) {
103 if (mGestureInfo[i].device_name == NULL)
104 continue;
105 activate(i + CROS_EC_MAX_PHYSICAL_SENSOR, 0);
106 }
107 if (cros_ec_sysfs_set_input_attr_by_int(mRingPath, "buffer/enable", 0) < 0) {
108 ALOGE("disable IIO buffer failed: %s\n", strerror(errno));
109 return;
110 }
111 close(mDataFd);
112 }
113
114 /*
115 * getFd: retrieve the ring file descriptor.
116 *
117 * Needed for CrosECSensor creator to listen to the buffer.
118 */
getFd(void)119 int CrosECSensor::getFd(void)
120 {
121 return mDataFd;
122 }
123
124 /*
125 * flush: Flush entry point.
126 *
127 * Issue the flush for a particular sensor to the EC via iio.
128 */
flush(int handle)129 int CrosECSensor::flush(int handle)
130 {
131 if (handle >= CROS_EC_MAX_PHYSICAL_SENSOR) {
132 struct cros_ec_gesture_info* info = &mGestureInfo[handle - CROS_EC_MAX_PHYSICAL_SENSOR];
133 if (info->sensor_data.flags & SENSOR_FLAG_ONE_SHOT_MODE)
134 return -EINVAL;
135 /* not expected, current gestures are all one-shot. */
136 return -EINVAL;
137 } else {
138 struct cros_ec_sensor_info *info = &mSensorInfo[handle];
139
140 if (!info->enabled)
141 return -EINVAL;
142
143 return cros_ec_sysfs_set_input_attr_by_int(info->device_name, "flush", 1);
144 }
145 }
146
147 /*
148 * activate: Activate entry point.
149 *
150 * When enabled set the sensor frequency. If not enabled, set
151 * the sensor in suspend mode by setting the frequency to 0.
152 */
activate(int handle,int enabled)153 int CrosECSensor::activate(int handle, int enabled)
154 {
155 int err;
156 if (handle < CROS_EC_MAX_PHYSICAL_SENSOR) {
157 struct cros_ec_sensor_info *info = &mSensorInfo[handle];
158 /*
159 * Frequency is in mHz, sampling period in ns, use 10^(9 + 3)
160 * coefficient.
161 */
162 long frequency = enabled ? 1e12 / info->sampling_period_ns : 0;
163
164 err = cros_ec_sysfs_set_input_attr_by_int(info->device_name,
165 "frequency", frequency);
166 if (err)
167 return err;
168
169 long ec_period = nanoseconds_to_milliseconds(info->max_report_latency_ns);
170
171 if (enabled)
172 ec_period = min(CROS_EC_MAX_SAMPLING_PERIOD, ec_period);
173 else
174 ec_period = 0;
175
176 /* Sampling is encoded on a 16bit so, so the maximal period is ~65s. */
177 err = cros_ec_sysfs_set_input_attr_by_int(
178 info->device_name, "sampling_frequency", ec_period);
179 if (!err)
180 info->enabled = enabled;
181 } else {
182 struct cros_ec_gesture_info* info = &mGestureInfo[handle - CROS_EC_MAX_PHYSICAL_SENSOR];
183 char attr[PATH_MAX] = "events/";
184 strcat(attr, info->enable_entry);
185 err = cros_ec_sysfs_set_input_attr_by_int(info->device_name, attr, enabled);
186 if (!err)
187 info->enabled = enabled;
188 }
189
190 return err;
191 }
192
193 /*
194 * batch: Batch entry point.
195 *
196 * Set the EC sampling frequency. Check boundaries to prevent polling too fast.
197 */
batch(int handle,int64_t sampling_period_ns,int64_t max_report_latency_ns)198 int CrosECSensor::batch(int handle,
199 int64_t sampling_period_ns,
200 int64_t max_report_latency_ns)
201 {
202 if (handle < CROS_EC_MAX_PHYSICAL_SENSOR) {
203 struct cros_ec_sensor_info *info = &mSensorInfo[handle];
204
205 info->max_report_latency_ns = max_report_latency_ns;
206
207 if (nanoseconds_to_microseconds(sampling_period_ns) >
208 info->sensor_data.maxDelay)
209 info->sampling_period_ns = microseconds_to_nanoseconds(info->sensor_data.maxDelay);
210 else if (nanoseconds_to_microseconds(sampling_period_ns) <
211 info->sensor_data.minDelay)
212 info->sampling_period_ns = microseconds_to_nanoseconds(info->sensor_data.minDelay);
213 else
214 info->sampling_period_ns = sampling_period_ns;
215
216 /*
217 * Note that the sensor hub limit minimal sampling frequency at few ms.
218 * Which is good, because HAL shold not ask for polling sensor at
219 * more than the sampling period, set in sensor_t.
220 */
221 if (info->max_report_latency_ns < max(sampling_period_ns, info->sampling_period_ns)) {
222 /*
223 * We have to report an event as soon as available.
224 * Set polling frequency as low as sampling frequency
225 */
226 info->max_report_latency_ns = max(sampling_period_ns, info->sampling_period_ns);
227 }
228
229
230 /* Call activate to change the paramters if necessary */
231 return activate(handle, info->enabled);
232 } else {
233 return 0;
234 }
235 }
236
237 /*
238 * readEvents: Read events from the iio ring buffer.
239 *
240 * data: where to put the events.
241 * count: maximal number of events to read from iio.
242 * If iio indicates no more events are available, return.
243 */
readEvents(sensors_event_t * data,int count)244 int CrosECSensor::readEvents(sensors_event_t* data, int count)
245 {
246 int rc;
247
248 if (count < 1) {
249 return -EINVAL;
250 }
251
252 /*
253 * Do a single read to collects all pending events.
254 * up to what poll caller can handle.
255 */
256 rc = read(mDataFd, mEvents, sizeof(cros_ec_event) * count);
257 if (rc < 0) {
258 ALOGE("rc %d while reading ring\n", rc);
259 return rc;
260 }
261 if (rc % sizeof(cros_ec_event) != 0) {
262 ALOGE("Incomplete event while reading ring: %d\n", rc);
263 return -EINVAL;
264 }
265
266 int nb_events = rc / sizeof(cros_ec_event);
267 int data_events = 0;
268 for (int i = 0; i < nb_events; i++) {
269 rc = processEvent(data, &mEvents[i]);
270 if (rc == 0) {
271 data++;
272 data_events++;
273 }
274 }
275
276 return data_events;
277 }
278
279 /*
280 * processEvent:
281 *
282 * Internal function to translate an event from the iio ring
283 * buffer into a sensors_event_t.
284 *
285 * Support flush meta event and regular events.
286 */
processEvent(sensors_event_t * data,const cros_ec_event * event)287 int CrosECSensor::processEvent(sensors_event_t* data, const cros_ec_event *event)
288 {
289 if (event->flags & CROS_EC_EVENT_FLUSH_FLAG) {
290 data->version = META_DATA_VERSION;
291 data->sensor = 0;
292 data->type = SENSOR_TYPE_META_DATA;
293 data->reserved0 = 0;
294 data->timestamp = 0;
295 data->meta_data.what = META_DATA_FLUSH_COMPLETE;
296 data->meta_data.sensor = event->sensor_id;
297 return 0;
298 }
299
300 if (event->sensor_id >= mSensorNb) {
301 return -EINVAL;
302 }
303 struct cros_ec_sensor_info *info = &mSensorInfo[event->sensor_id];
304
305 if (info->type == CROS_EC_ACTIVITY) {
306 ALOGI("Activity: %d - state: %d\n", event->activity, event->state);
307 if (event->activity >= mGestureNb)
308 return -ENOKEY;
309
310 struct cros_ec_gesture_info *gesture = &mGestureInfo[event->activity];
311 if (!gesture->enabled)
312 return -ENOKEY;
313
314 data->version = sizeof(sensors_event_t);
315 data->sensor = CROS_EC_MAX_PHYSICAL_SENSOR + event->activity;
316 data->type = gesture->sensor_data.type;
317
318 /*
319 * bootime Timestamp coming from the kernel are not reliable when
320 * the system resume: very early, the sleep delay has not yet been added.
321 * Use the current time, not the kernel timestamp.
322 * chrome-os-partner:46724
323 */
324 data->timestamp = systemTime(SYSTEM_TIME_BOOTTIME);
325 data->data[0] = (float)event->state;
326
327 if (gesture->sensor_data.flags & SENSOR_FLAG_ONE_SHOT_MODE)
328 gesture->enabled = 0;
329 } else {
330
331 /*
332 * The sensor hub can send data even if the sensor is not set up.
333 * workaround it unitl b/23238991 is fixed.
334 */
335 if (!info->enabled)
336 return -ENOKEY;
337
338 data->version = sizeof(sensors_event_t);
339 data->sensor = event->sensor_id;
340 data->type = info->sensor_data.type;
341 data->timestamp = event->timestamp;
342 data->acceleration.status = SENSOR_STATUS_ACCURACY_LOW;
343
344 /*
345 * Even for sensor with one axis (light, proxmity), be sure to write
346 * the other vectors. EC 0s them out.
347 */
348 float d;
349 for (int i = X ; i < MAX_AXIS; i++) {
350 switch (info->sensor_data.type) {
351 case SENSOR_TYPE_ACCELEROMETER:
352 case SENSOR_TYPE_GYROSCOPE:
353 case SENSOR_TYPE_MAGNETIC_FIELD:
354 d = event->vector[i];
355 break;
356 case SENSOR_TYPE_LIGHT:
357 case SENSOR_TYPE_PROXIMITY:
358 d = (uint16_t)event->vector[i];
359 break;
360 default:
361 return -EINVAL;
362 }
363 data->acceleration.v[i] =
364 d * mSensorInfo[event->sensor_id].sensor_data.resolution;
365 }
366 }
367 return 0;
368 }
369
370
371 /*
372 * cros_ec_sysfs_get_attr: Helper function to read sysfs attributes.
373 *
374 * path: the path of the device.
375 * attr: attribute to read (path/attr)
376 * output: where to put the string read.
377 */
cros_ec_sysfs_get_attr(const char * path,const char * attr,char * output)378 int cros_ec_sysfs_get_attr(const char *path, const char *attr, char *output)
379 {
380 char name[IIO_MAX_DEVICE_NAME_LENGTH + 10];
381 strcpy(name, path);
382 strcat(name, "/");
383 strcat(name, attr);
384 int fd = open(name, O_RDONLY);
385 if (fd < 0) {
386 ALOGE("Unable to read %s\n", name);
387 return -errno;
388 }
389 int size = read(fd, output, IIO_MAX_NAME_LENGTH);
390 close(fd);
391 if (size == 0)
392 return -EINVAL;
393 if (output[size - 1] == '\n')
394 output[size - 1] = 0;
395 else
396 output[size] = 0;
397 return 0;
398 }
399
400 /*
401 * cros_ec_sysfs_set_input_attr: Helper function to write a sysfs attribute.
402 */
cros_ec_sysfs_set_input_attr(const char * path,const char * attr,const char * value,size_t len)403 int cros_ec_sysfs_set_input_attr(const char *path, const char *attr,
404 const char *value, size_t len)
405 {
406 char fname[PATH_MAX];
407 int fd;
408 int rc;
409
410 snprintf(fname, sizeof(fname), "%s%s/%s", IIO_DIR, path, attr);
411 fname[sizeof(fname) - 1] = '\0';
412
413 fd = open(fname, O_WRONLY);
414 if (fd < 0) {
415 ALOGE("%s: fname = %s, fd = %d, failed: %s\n", __func__,
416 fname, fd, strerror(errno));
417 return -EACCES;
418 }
419
420 rc = write(fd, value, (size_t)len);
421 if (rc < 0) {
422 ALOGE("%s: write failed: fd = %d, rc = %d, strerr = %s\n", __func__,
423 fd, rc, strerror(errno));
424 ALOGE("fname = %s, value = %s\n", fname, value);
425 }
426
427 close(fd);
428
429 return rc < 0 ? rc : 0;
430 }
431
cros_ec_sysfs_set_input_attr_by_int(const char * path,const char * attr,int value)432 int cros_ec_sysfs_set_input_attr_by_int(const char *path,
433 const char *attr, int value)
434 {
435 char buf[INT32_CHAR_LEN];
436
437 size_t n = snprintf(buf, sizeof(buf), "%d", value);
438 if (n > sizeof(buf)) {
439 return -1;
440 }
441
442 return cros_ec_sysfs_set_input_attr(path, attr, buf, n);
443 }
444