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 /*****************************************************************************/ 38 static int max(int a, int b) { 39 return (a > b) ? a : b; 40 } 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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