Home | History | Annotate | Download | only in sensor_hub
      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