X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=control.c;h=0f01939c582624b6ecf27d1e7b6bd47dab9803a2;hb=138a7ad03eb4ecdc5a68f53784e8883290c7e608;hp=d2d6d0cf73f44ebc69f09fe24de562a6a5a41831;hpb=64cf45171c61ee6e43ccf80383b80cf82b8c2cb5;p=android-x86%2Fhardware-intel-libsensors.git diff --git a/control.c b/control.c index d2d6d0c..0f01939 100644 --- a/control.c +++ b/control.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -14,6 +16,7 @@ #include "utils.h" #include "transform.h" #include "calibration.h" +#include "description.h" /* Currently active sensors count, per device */ static int poll_sensors_per_dev[MAX_DEVICES]; /* poll-mode sensors */ @@ -23,34 +26,81 @@ static int device_fd[MAX_DEVICES]; /* fd on the /dev/iio:deviceX file */ static int poll_fd; /* epoll instance covering all enabled sensors */ -static int poll_socket_pair[2]; /* used to unblock the poll loop */ +static int active_poll_sensors; /* Number of enabled poll-mode sensors */ -/* Timestamp for the moment when we last exited a poll operation */ -static int64_t last_poll_exit_ts; +int64_t ts_delta; /* delta between SystemClock.getNanos and our timestamp */ -static int active_poll_sensors; /* Number of enabled poll-mode sensors */ +/* We use pthread condition variables to get worker threads out of sleep */ +static pthread_condattr_t thread_cond_attr [MAX_SENSORS]; +static pthread_cond_t thread_release_cond [MAX_SENSORS]; +static pthread_mutex_t thread_release_mutex [MAX_SENSORS]; -#define INVALID_DEV_NUM ((uint32_t) -1) +/* + * We associate tags to each of our poll set entries. These tags have the + * following values: + * - a iio device number if the fd is a iio character device fd + * - THREAD_REPORT_TAG_BASE + sensor handle if the fd is the receiving end of a + * pipe used by a sysfs data acquisition thread + * */ +#define THREAD_REPORT_TAG_BASE 0x00010000 +#define ENABLE_BUFFER_RETRIES 10 +#define ENABLE_BUFFER_RETRY_DELAY_MS 10 static int enable_buffer(int dev_num, int enabled) { char sysfs_path[PATH_MAX]; + int ret, retries, millisec; + struct timespec req = {0}; + + retries = ENABLE_BUFFER_RETRIES; + millisec = ENABLE_BUFFER_RETRY_DELAY_MS; + req.tv_sec = 0; + req.tv_nsec = millisec * 1000000L; sprintf(sysfs_path, ENABLE_PATH, dev_num); - /* Low level, non-multiplexed, enable/disable routine */ - return sysfs_write_int(sysfs_path, enabled); + while (retries--) { + /* Low level, non-multiplexed, enable/disable routine */ + ret = sysfs_write_int(sysfs_path, enabled); + if (ret > 0) + break; + + ALOGE("Failed enabling buffer, retrying"); + nanosleep(&req, (struct timespec *)NULL); + } + + if (ret < 0) { + ALOGE("Could not enable buffer\n"); + return -EIO; + } + + return 0; } -static int setup_trigger(int dev_num, const char* trigger_val) +static int setup_trigger (int s, const char* trigger_val) { char sysfs_path[PATH_MAX]; + int ret = -1, attempts = 5; + + sprintf(sysfs_path, TRIGGER_PATH, sensor_info[s].dev_num); - sprintf(sysfs_path, TRIGGER_PATH, dev_num); + if (trigger_val[0] != '\n') + ALOGI("Setting S%d (%s) trigger to %s\n", s, + sensor_info[s].friendly_name, trigger_val); - return sysfs_write_str(sysfs_path, trigger_val); + while (ret == -1 && attempts) { + ret = sysfs_write_str(sysfs_path, trigger_val); + attempts--; + } + + if (ret != -1) + sensor_info[s].selected_trigger = trigger_val; + else + ALOGE("Setting S%d (%s) trigger to %s FAILED.\n", s, + sensor_info[s].friendly_name, trigger_val); + return ret; } @@ -149,7 +199,7 @@ void build_sensor_report_maps(int dev_num) /* Stop sampling - if we are recovering from hal restart */ enable_buffer(dev_num, 0); - setup_trigger(dev_num, "\n"); + setup_trigger(s, "\n"); /* Turn on channels we're aware of */ for (c=0;c 1) return 0; /* The sensor was, and remains, in use */ - } else { - if (sensor_type == SENSOR_TYPE_MAGNETIC_FIELD) + + switch (sensor_type) { + case SENSOR_TYPE_MAGNETIC_FIELD: compass_read_data(&sensor_info[s]); + break; - if (sensor_type == SENSOR_TYPE_GYROSCOPE) + case SENSOR_TYPE_GYROSCOPE: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: gyro_cal_init(&sensor_info[s]); + break; } } else { if (sensor_info[s].enable_count == 0) @@ -228,9 +282,6 @@ int adjust_counters (int s, int enabled) ALOGI("Disabling sensor %d (iio device %d: %s)\n", s, dev_num, sensor_info[s].friendly_name); - if (sensor_type == SENSOR_TYPE_MAGNETIC_FIELD) - compass_store_data(&sensor_info[s]); - sensor_info[s].enable_count--; if (sensor_info[s].enable_count > 0) @@ -238,8 +289,17 @@ int adjust_counters (int s, int enabled) /* Sensor disabled, lower report available flag */ sensor_info[s].report_pending = 0; + + if (sensor_type == SENSOR_TYPE_MAGNETIC_FIELD) + compass_store_data(&sensor_info[s]); } + + /* If uncalibrated type and pair is already active don't adjust counters */ + if (sensor_type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED && + sensor_info[sensor_info[s].pair_idx].enable_count != 0) + return 0; + /* We changed the state of a sensor - adjust per iio device counters */ /* If this is a regular event-driven sensor */ @@ -265,37 +325,256 @@ int adjust_counters (int s, int enabled) } +static int get_field_count (int s) +{ + int catalog_index = sensor_info[s].catalog_index; + int sensor_type = sensor_catalog[catalog_index].type; + + switch (sensor_type) { + case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */ + case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */ + case SENSOR_TYPE_ORIENTATION: /* degrees */ + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_GYROSCOPE: /* radians/s */ + return 3; + + case SENSOR_TYPE_LIGHT: /* SI lux units */ + case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */ + case SENSOR_TYPE_TEMPERATURE: /* °C */ + case SENSOR_TYPE_PROXIMITY: /* centimeters */ + case SENSOR_TYPE_PRESSURE: /* hecto-pascal */ + case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */ + return 1; + + case SENSOR_TYPE_ROTATION_VECTOR: + return 4; + + default: + ALOGE("Unknown sensor type!\n"); + return 0; /* Drop sample */ + } +} + + + +static void* acquisition_routine (void* param) +{ + /* + * Data acquisition routine run in a dedicated thread, covering a single + * sensor. This loop will periodically retrieve sampling data through + * sysfs, then package it as a sample and transfer it to our master poll + * loop through a report fd. Checks for a cancellation signal quite + * frequently, as the thread may be disposed of at any time. Note that + * Bionic does not provide pthread_cancel / pthread_testcancel... + */ + + int s = (int) (size_t) param; + int num_fields, sample_size; + struct sensors_event_t data = {0}; + int c; + int ret; + struct timespec target_time; + int64_t timestamp, period; + + if (s < 0 || s >= sensor_count) { + ALOGE("Invalid sensor handle!\n"); + return NULL; + } + + ALOGI("Entering data acquisition thread S%d (%s): rate(%f), ts(%lld)\n", s, + sensor_info[s].friendly_name, sensor_info[s].sampling_rate, sensor_info[s].report_ts); + + if (sensor_info[s].sampling_rate <= 0) { + ALOGE("Non-positive rate in acquisition routine for sensor %d: %f\n", + s, sensor_info[s].sampling_rate); + return NULL; + } + + num_fields = get_field_count(s); + sample_size = num_fields * sizeof(float); + + /* + * Each condition variable is associated to a mutex that has to be + * locked by the thread that's waiting on it. We use these condition + * variables to get the acquisition threads out of sleep quickly after + * the sampling rate is adjusted, or the sensor is disabled. + */ + pthread_mutex_lock(&thread_release_mutex[s]); + + /* Pinpoint the moment we start sampling */ + timestamp = get_timestamp_monotonic(); + + /* Check and honor termination requests */ + while (sensor_info[s].thread_data_fd[1] != -1) { + + /* Read values through sysfs */ + for (c=0; c (th <= 1.1111) + */ +#define THRESHOLD 1.10 +void set_report_ts(int s, int64_t ts) +{ + int64_t maxTs, period; + int catalog_index = sensor_info[s].catalog_index; + int is_accel = (sensor_catalog[catalog_index].type == SENSOR_TYPE_ACCELEROMETER); + + /* + * A bit of a hack to please a bunch of cts tests. They + * expect the timestamp to be exacly according to the set-up + * frequency but if we're simply getting the timestamp at hal level + * this may not be the case. Perhaps we'll get rid of this when + * we'll be reading the timestamp from the iio channel for all sensors + */ + if (sensor_info[s].report_ts && sensor_info[s].sampling_rate && + REPORTING_MODE(sensor_desc[s].flags) == SENSOR_FLAG_CONTINUOUS_MODE) + { + period = (int64_t) (1000000000LL / sensor_info[s].sampling_rate); + maxTs = sensor_info[s].report_ts + (is_accel ? 1 : THRESHOLD) * period; + sensor_info[s].report_ts = (ts < maxTs ? ts : maxTs); + } else { + sensor_info[s].report_ts = ts; + } +} + static int integrate_device_report(int dev_num) { int len; @@ -373,9 +784,8 @@ static int integrate_device_report(int dev_num) unsigned char *target; unsigned char *source; int size; - int ts; - /* There's an incoming report on the specified fd */ + /* 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); @@ -387,7 +797,7 @@ static int integrate_device_report(int dev_num) return -1; } - ts = get_timestamp(); + len = read(device_fd[dev_num], buf, MAX_SENSOR_REPORT_SIZE); @@ -399,6 +809,8 @@ static int integrate_device_report(int dev_num) ALOGV("Read %d bytes from iio device %d\n", len, dev_num); + /* Map device report to sensor reports */ + for (s=0; sversion = sizeof(sensors_event_t); - data->sensor = s; - data->type = sensor_type; - if (sensor_info[s].report_ts) - data->timestamp = sensor_info[s].report_ts; - else - data->timestamp = current_ts; - - switch (sensor_type) { - case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */ - case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */ - case SENSOR_TYPE_ORIENTATION: /* degrees */ - case SENSOR_TYPE_GYROSCOPE: /* radians/s */ - num_fields = 3; - break; + /* If there's nothing to return... we're done */ + if (!num_fields) + return 0; - case SENSOR_TYPE_LIGHT: /* SI lux units */ - case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */ - case SENSOR_TYPE_TEMPERATURE: /* °C */ - case SENSOR_TYPE_PROXIMITY: /* centimeters */ - case SENSOR_TYPE_PRESSURE: /* hecto-pascal */ - case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */ - num_fields = 1; - break; - case SENSOR_TYPE_ROTATION_VECTOR: - num_fields = 4; - break; + /* Only return uncalibrated event if also gyro active */ + if (sensor_type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED && + sensor_info[sensor_info[s].pair_idx].enable_count != 0) + return 0; - case SENSOR_TYPE_DEVICE_PRIVATE_BASE: /* Hidden for now */ - return 0; /* Drop sample */ + memset(data, 0, sizeof(sensors_event_t)); - default: - ALOGE("Unknown sensor type!\n"); - return 0; /* Drop sample */ - } + data->version = sizeof(sensors_event_t); + data->sensor = s; + data->type = sensor_type; + data->timestamp = sensor_info[s].report_ts; ALOGV("Sample on sensor %d (type %d):\n", s, sensor_type); - /* Take note of current time counter value for rate control purposes */ - sensor_info[s].last_integration_ts = current_ts; + current_sample = sensor_info[s].report_buffer; - /* If we're dealing with a poll-mode sensor */ + /* If this is a poll sensor */ if (!sensor_info[s].num_channels) { - - /* Read values through sysfs rather than from a report buffer */ - for (c=0; cdata[c] = acquire_immediate_value(s, c); - - ALOGV("\tfield %d: %f\n", c, data->data[c]); - } - - /* Control acquisition time and flag anything beyond 100 ms */ - delta = get_timestamp() - current_ts; - - if (delta > 100 * 1000 * 1000) { - ALOGI("Sensor %d (%s) sampling time: %d ms\n", s, - sensor_info[s].friendly_name, (int) (delta / 1000000)); - } - - return sensor_info[s].ops.finalize(s, data); + /* Use the data provided by the acquisition thread */ + ALOGV("Reporting data from worker thread for S%d\n", s); + memcpy(data->data, current_sample, num_fields * sizeof(float)); + return 1; } /* Convert the data into the expected Android-level format */ - - current_sample = sensor_info[s].report_buffer; - for (c=0; cdata[c] = sensor_info[s].ops.transform @@ -531,48 +904,119 @@ static int propagate_sensor_report(int s, struct sensors_event_t* data) } -static int get_poll_time (void) +static void synthetize_duplicate_samples (void) { - int64_t target_ts; - int64_t lowest_target_ts; - int64_t current_ts; + /* + * Some sensor types (ex: gyroscope) are defined as continuously firing + * by Android, despite the fact that we can be dealing with iio drivers + * that only report events for new samples. For these we generate + * reports periodically, duplicating the last data we got from the + * driver. This is not necessary for polling sensors. + */ + int s; + int64_t current_ts; + int64_t target_ts; + int64_t period; - if (!active_poll_sensors) - return -1; /* Infinite wait */ + for (s=0; s 0 && - !sensor_info[s].num_channels) { - target_ts = sensor_info[s].last_integration_ts + - 1000000000LL/sensor_info[s].sampling_rate; + /* If we haven't seen a sample, there's nothing to duplicate */ + if (!sensor_info[s].report_initialized) + continue; - if (target_ts < lowest_target_ts) - lowest_target_ts = target_ts; - } + /* If a sample was recently buffered, leave it alone too */ + if (sensor_info[s].report_pending) + continue; - if (lowest_target_ts == INT64_MAX) - return -1; + /* We also need a valid sampling rate to be configured */ + if (!sensor_info[s].sampling_rate) + continue; - current_ts = get_timestamp(); + period = (int64_t) (1000000000.0/ sensor_info[s].sampling_rate); - if (lowest_target_ts <= current_ts) - return 0; + current_ts = get_timestamp(); + target_ts = sensor_info[s].report_ts + period; - return (lowest_target_ts - current_ts)/1000000; /* ms */ + if (target_ts <= current_ts) { + /* Mark the sensor for event generation */ + set_report_ts(s, current_ts); + sensor_info[s].report_pending = 1; + } + } } -static void acknowledge_release (void) +static void integrate_thread_report (uint32_t tag) { - /* A write to our socket circuit was performed to release epoll */ - char buf; - read(poll_socket_pair[0], &buf, 1); + int s = tag - THREAD_REPORT_TAG_BASE; + int len; + int expected_len; + + expected_len = get_field_count(s) * sizeof(float); + + len = read(sensor_info[s].thread_data_fd[0], + sensor_info[s].report_buffer, + expected_len); + + if (len == expected_len) { + set_report_ts(s, get_timestamp()); + sensor_info[s].report_pending = 1; + } +} + + +static int get_poll_wait_timeout (void) +{ + /* + * Compute an appropriate timeout value, in ms, for the epoll_wait + * call that's going to await for iio device reports and incoming + * reports from our sensor sysfs data reader threads. + */ + + int s; + int64_t target_ts = INT64_MAX; + int64_t ms_to_wait; + int64_t period; + + /* + * Check if we're dealing with a driver that only send events when + * there is motion, despite the fact that the associated Android sensor + * type is continuous rather than on-change. In that case we have to + * duplicate events. Check deadline for the nearest upcoming event. + */ + for (s=0; sbias_x; + data[uncal_start + i].data[1] = data[returned_events + i].data[1] + gyro_data->bias_y; + data[uncal_start + i].data[2] = data[returned_events + i].data[2] + gyro_data->bias_z; + + data[uncal_start + i].uncalibrated_gyro.bias[0] = gyro_data->bias_x; + data[uncal_start + i].uncalibrated_gyro.bias[1] = gyro_data->bias_y; + data[uncal_start + i].uncalibrated_gyro.bias[2] = gyro_data->bias_z; + } + event_count <<= 1; + } + sensor_info[sensor_info[s].pair_idx].report_pending = 0; + returned_events += event_count; /* * If the sample was deemed invalid or unreportable, * e.g. had the same value as the previously reported - * value for a 'on change' sensor, silently drop it + * value for a 'on change' sensor, silently drop it. */ } + while (sensor_info[s].meta_data_pending) { + /* See sensors.h on these */ + data[returned_events].version = META_DATA_VERSION; + data[returned_events].sensor = 0; + data[returned_events].type = SENSOR_TYPE_META_DATA; + data[returned_events].reserved0 = 0; + data[returned_events].timestamp = 0; + data[returned_events].meta_data.sensor = s; + data[returned_events].meta_data.what = META_DATA_FLUSH_COMPLETE; + returned_events++; + sensor_info[s].meta_data_pending--; + } + } + if (returned_events) + return returned_events; + await_event: ALOGV("Awaiting sensor data\n"); - nfds = epoll_wait(poll_fd, ev, MAX_DEVICES, get_poll_time()); - - last_poll_exit_ts = get_timestamp(); + nfds = epoll_wait(poll_fd, ev, MAX_DEVICES, get_poll_wait_timeout()); if (nfds == -1) { - ALOGI("epoll_wait returned -1 (%s)\n", strerror(errno)); + ALOGE("epoll_wait returned -1 (%s)\n", strerror(errno)); goto await_event; } ALOGV("%d fds signalled\n", nfds); - /* For each of the devices for which a report is available */ + /* For each of the signalled sources */ for (i=0; i 0) { - target_ts = sensor_info[s].last_integration_ts + - 1000000000LL/sensor_info[s].sampling_rate; - - if (last_poll_exit_ts >= target_ts) - sensor_info[s].report_pending = 1; + if (ev[i].events == EPOLLIN) + switch (ev[i].data.u32) { + case 0 ... MAX_DEVICES-1: + /* Read report from iio char dev fd */ + integrate_device_report(ev[i].data.u32); + break; + + case THREAD_REPORT_TAG_BASE ... + THREAD_REPORT_TAG_BASE + MAX_SENSORS-1: + /* Get report from acquisition thread */ + integrate_thread_report(ev[i].data.u32); + break; + + default: + ALOGW("Unexpected event source!\n"); + break; } - goto return_first_available_sensor_report; + goto return_available_sensor_reports; +} + + +static void tentative_switch_trigger (int s) +{ + /* + * Under certain situations it may be beneficial to use an alternate + * trigger: + * + * - for applications using the accelerometer with high sampling rates, + * prefer the continuous trigger over the any-motion one, to avoid + * jumps related to motion thresholds + */ + + if (is_fast_accelerometer(s) && + !(sensor_info[s].quirks & QUIRK_TERSE_DRIVER) && + sensor_info[s].selected_trigger == + sensor_info[s].motion_trigger_name) + setup_trigger(s, sensor_info[s].init_trigger_name); } @@ -664,32 +1165,49 @@ int sensor_set_delay(int s, int64_t ns) const char *prefix = sensor_catalog[i].tag; float new_sampling_rate; /* Granted sampling rate after arbitration */ float cur_sampling_rate; /* Currently used sampling rate */ - float req_sampling_rate; /* Requested ; may be different from granted */ int per_sensor_sampling_rate; int per_device_sampling_rate; - int max_supported_rate = 0; + int32_t min_delay_us = sensor_desc[s].minDelay; + max_delay_t max_delay_us = sensor_desc[s].maxDelay; + float min_supported_rate = max_delay_us ? (1000000.0f / max_delay_us) : 1; + float max_supported_rate = + (min_delay_us && min_delay_us != -1) ? (1000000.0f / min_delay_us) : 0; char freqs_buf[100]; char* cursor; int n; - int sr; + float sr; - if (!ns) { - ALOGE("Rejecting zero delay request on sensor %d\n", s); + if (ns <= 0) { + ALOGE("Rejecting non-positive delay request on sensor %d, required delay: %lld\n", s, ns); return -EINVAL; } - new_sampling_rate = req_sampling_rate = 1000000000L/ns; + new_sampling_rate = 1000000000LL/ns; + + ALOGV("Entering set delay S%d (%s): old rate(%f), new rate(%f)\n", + s, sensor_info[s].friendly_name, sensor_info[s].sampling_rate, + new_sampling_rate); + + /* + * Artificially limit ourselves to 1 Hz or higher. This is mostly to + * avoid setting up the stage for divisions by zero. + */ + if (new_sampling_rate < min_supported_rate) + new_sampling_rate = min_supported_rate; - if (new_sampling_rate < 1) { - ALOGI("Sub-HZ sampling rate requested on on sensor %d\n", s); - new_sampling_rate = 1; + if (max_supported_rate && + new_sampling_rate > max_supported_rate) { + new_sampling_rate = max_supported_rate; } sensor_info[s].sampling_rate = new_sampling_rate; - /* If we're dealing with a poll-mode sensor, release poll and return */ - if (!sensor_info[s].num_channels) - goto exit; + /* If we're dealing with a poll-mode sensor */ + if (!sensor_info[s].num_channels) { + /* Interrupt current sleep so the new sampling gets used */ + pthread_cond_signal(&thread_release_cond[s]); + return 0; + } sprintf(sysfs_path, SENSOR_SAMPLING_PATH, dev_num, prefix); @@ -736,13 +1254,6 @@ int sensor_set_delay(int s, int64_t ns) /* Decode a single value */ sr = strtod(cursor, NULL); - /* Cap sampling rate to CAP_SENSOR_MAX_FREQUENCY*/ - if (sr > CAP_SENSOR_MAX_FREQUENCY) - break; - - if (sr > max_supported_rate) - max_supported_rate = sr; - /* If this matches the selected rate, we're happy */ if (new_sampling_rate == sr) break; @@ -755,10 +1266,6 @@ int sensor_set_delay(int s, int64_t ns) * in the allowed frequencies string. */ if (sr > new_sampling_rate) { - ALOGI( - "Increasing sampling rate on sensor %d from %g to %g\n", - s, (double) req_sampling_rate, (double) sr); - new_sampling_rate = sr; break; } @@ -773,42 +1280,45 @@ int sensor_set_delay(int s, int64_t ns) } } - if (max_supported_rate && new_sampling_rate > max_supported_rate) { new_sampling_rate = max_supported_rate; - ALOGI( "Can't support %g sampling rate, lowering to %g\n", - (double) req_sampling_rate, (double) new_sampling_rate); } - /* If the desired rate is already active we're all set */ if (new_sampling_rate == cur_sampling_rate) return 0; - ALOGI("Sensor %d sampling rate switched to %g\n", s, new_sampling_rate); + ALOGI("Sensor %d sampling rate set to %g\n", s, new_sampling_rate); if (trig_sensors_per_dev[dev_num]) enable_buffer(dev_num, 0); sysfs_write_float(sysfs_path, new_sampling_rate); + /* Check if it makes sense to use an alternate trigger */ + tentative_switch_trigger(s); + if (trig_sensors_per_dev[dev_num]) enable_buffer(dev_num, 1); -exit: - /* Release the polling loop so an updated timeout value gets used */ - write(poll_socket_pair[1], "", 1); - return 0; } +int sensor_flush (int s) +{ + /* If one shot or not enabled return -EINVAL */ + if (sensor_desc[s].flags & SENSOR_FLAG_ONE_SHOT_MODE || + sensor_info[s].enable_count == 0) + return -EINVAL; + sensor_info[s].meta_data_pending++; + return 0; +} int allocate_control_data (void) { int i; - struct epoll_event ev = {0}; for (i=0; i