2 // Copyright (c) 2015 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <utils/Log.h>
20 #include <cutils/properties.h>
21 #include <hardware/sensors.h>
23 #include "enumeration.h"
24 #include "description.h"
26 #include "transform.h"
28 #define IIO_SENSOR_HAL_VERSION 1
30 #define MIN_ON_CHANGE_SAMPLING_PERIOD_US 200000 /* For on change sensors (temperature, proximity, ALS, etc.) report we support 5 Hz max (0.2 s min period) */
31 #define MAX_ON_CHANGE_SAMPLING_PERIOD_US 10000000 /* 0.1 Hz min (10 s max period)*/
32 #define ANDROID_MAX_FREQ 1000 /* 1000 Hz - This is how much Android requests for the fastest frequency */
37 * We acquire a number of parameters about sensors by reading properties.
38 * The idea here is that someone (either a script, or daemon, sets them
39 * depending on the set of sensors present on the machine.
41 * There are fallback paths in case the properties are not defined, but it is
42 * highly desirable to at least have the following for each sensor:
44 * ro.iio.anglvel.name = Gyroscope
45 * ro.iio.anglvel.vendor = Intel
46 * ro.iio.anglvel.max_range = 35
47 * ro.iio.anglvel.resolution = 0.002
48 * ro.iio.anglvel.power = 6.1
50 * Besides these, we have a couple of knobs initially used to cope with Intel
51 * Sensor Hub oddities, such as HID inspired units or firmware bugs:
53 * ro.iio.anglvel.transform = ISH
54 * ro.iio.anglvel.quirks = init-rate
56 * The "terse" quirk indicates that the underlying driver only sends events
57 * when the sensor reports a change. The HAL then periodically generates
58 * duplicate events so the sensor behaves as a continously firing one.
60 * The "noisy" quirk indicates that the underlying driver has a unusually high
61 * level of noise in its readings, and that the HAL has to accomodate it
62 * somehow, e.g. in the magnetometer calibration code path.
64 * This one is used specifically to pass a calibration scale to ALS drivers:
66 * ro.iio.illuminance.name = CPLM3218x Ambient Light Sensor
67 * ro.iio.illuminance.vendor = Capella Microsystems
68 * ro.iio.illuminance.max_range = 167000
69 * ro.iio.illuminance.resolution = 1
70 * ro.iio.illuminance.power = .001
71 * ro.iio.illuminance.illumincalib = 7400
73 * There's a 'opt_scale' specifier, documented as follows:
75 * This adds support for a scaling factor that can be expressed
76 * using properties, for all sensors, on a channel basis. That
77 * scaling factor is applied after all other transforms have been
78 * applied, and is intended as a way to compensate for problems
79 * such as an incorrect axis polarity for a given sensor.
81 * The syntax is <usual property prefix>.<channel>.opt_scale, e.g.
82 * ro.iio.accel.y.opt_scale = -1 to negate the sign of the y readings
83 * for the accelerometer.
85 * For sensors using a single channel - and only those - the channel
86 * name is implicitly void and a syntax such as ro.iio.illuminance.
87 * opt_scale = 3 has to be used.
89 * 'panel' and 'rotation' specifiers can be used to express ACPI PLD placement
90 * information ; if found they will be used in priority over the actual ACPI
91 * data. That is intended as a way to verify values during development.
93 * It's possible to use the contents of the iio device name as a way to
94 * discriminate between sensors. Several sensors of the same type can coexist:
95 * e.g. ro.iio.temp.bmg160.name = BMG160 Thermometer will be used in priority
96 * over ro.iio.temp.name = BMC150 Thermometer if the sensor for which we query
97 * properties values happen to have its iio device name set to bmg160.
100 int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE])
102 char prop_name[PROP_NAME_MAX];
103 char prop_val[PROP_VALUE_MAX];
104 char extended_sel[PROP_VALUE_MAX];
106 int i = sensor[s].catalog_index;
107 const char *prefix = sensor_catalog[i].tag;
108 const char *shorthand = sensor_catalog[i].shorthand;
110 /* First try most specialized form, like ro.iio.anglvel.bmg160.name */
112 snprintf(extended_sel, PROP_NAME_MAX, "%s.%s",
113 sensor[s].internal_name, sel);
115 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, extended_sel);
117 if (property_get(prop_name, prop_val, "")) {
118 strncpy(val, prop_val, MAX_NAME_SIZE-1);
119 val[MAX_NAME_SIZE-1] = '\0';
123 if (shorthand[0] != '\0') {
124 /* Try with shorthand instead of prefix */
125 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, shorthand, extended_sel);
127 if (property_get(prop_name, prop_val, "")) {
128 strncpy(val, prop_val, MAX_NAME_SIZE-1);
129 val[MAX_NAME_SIZE-1] = '\0';
133 /* Fall back to simple form, like ro.iio.anglvel.name */
135 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, sel);
137 if (property_get(prop_name, prop_val, "")) {
138 strncpy(val, prop_val, MAX_NAME_SIZE-1);
139 val[MAX_NAME_SIZE-1] = '\0';
147 int sensor_get_prop (int s, const char* sel, int* val)
149 char buf[MAX_NAME_SIZE];
151 if (sensor_get_st_prop(s, sel, buf))
159 int sensor_get_fl_prop (int s, const char* sel, float* val)
161 char buf[MAX_NAME_SIZE];
163 if (sensor_get_st_prop(s, sel, buf))
166 *val = (float) strtod(buf, NULL);
171 char* sensor_get_name (int s)
173 char buf[MAX_NAME_SIZE];
175 if (sensor[s].is_virtual) {
176 switch (sensor[s].type) {
177 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
178 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
179 strcpy(buf, sensor[sensor[s].base[0]].friendly_name);
180 snprintf(sensor[s].friendly_name,
182 "%s %s", "Uncalibrated", buf);
183 return sensor[s].friendly_name;
190 if (sensor[s].friendly_name[0] != '\0' ||
191 !sensor_get_st_prop(s, "name", sensor[s].friendly_name))
192 return sensor[s].friendly_name;
194 /* If we got a iio device name from sysfs, use it */
195 if (sensor[s].internal_name[0]) {
196 snprintf(sensor[s].friendly_name, MAX_NAME_SIZE, "S%d-%s",
197 s, sensor[s].internal_name);
199 sprintf(sensor[s].friendly_name, "S%d", s);
202 return sensor[s].friendly_name;
206 char* sensor_get_vendor (int s)
208 if (sensor[s].is_virtual) {
209 switch (sensor[s].type) {
210 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
211 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
212 return sensor[sensor[s].base[0]].vendor_name;
221 if (sensor[s].vendor_name[0] ||
222 !sensor_get_st_prop(s, "vendor", sensor[s].vendor_name))
223 return sensor[s].vendor_name;
229 int sensor_get_version (__attribute__((unused)) int s)
231 return IIO_SENSOR_HAL_VERSION;
234 void sensor_update_max_range(int s)
236 if (sensor[s].max_range)
239 if (sensor[s].num_channels && sensor[s].channel[0].type_info.realbits) {
240 switch (sensor[s].type) {
241 case SENSOR_TYPE_MAGNETIC_FIELD:
242 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
243 CONVERT_MICROTESLA_TO_GAUSS(sensor[s].resolution) +
244 (sensor[s].offset || sensor[s].channel[0].offset);
245 sensor[s].max_range = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].max_range);
247 case SENSOR_TYPE_PROXIMITY:
250 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
251 sensor[s].resolution + (sensor[s].offset || sensor[s].channel[0].offset);
256 if (!sensor[s].max_range) {
257 /* Try returning a sensible value given the sensor type */
258 /* We should cap returned samples accordingly... */
259 switch (sensor[s].type) {
260 case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
261 sensor[s].max_range = 50;
263 case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
264 sensor[s].max_range = 500;
266 case SENSOR_TYPE_ORIENTATION: /* degrees */
267 sensor[s].max_range = 360;
269 case SENSOR_TYPE_GYROSCOPE: /* radians/s */
270 sensor[s].max_range = 10;
272 case SENSOR_TYPE_LIGHT: /* SI lux units */
273 sensor[s].max_range = 50000;
275 case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
276 case SENSOR_TYPE_TEMPERATURE: /* °C */
277 case SENSOR_TYPE_PROXIMITY: /* centimeters */
278 case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
279 case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
280 sensor[s].max_range = 100;
285 if (sensor[s].max_range)
286 sensor_desc[s].maxRange = sensor[s].max_range;
289 float sensor_get_max_range (int s)
291 if (sensor[s].is_virtual) {
292 switch (sensor[s].type) {
293 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
294 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
295 return sensor[sensor[s].base[0]].max_range;
302 if (sensor[s].max_range != 0.0 ||
303 !sensor_get_fl_prop(s, "max_range", &sensor[s].max_range))
304 return sensor[s].max_range;
309 float sensor_get_min_freq (int s)
312 * Check if a low cap has been specified for this sensor sampling rate.
313 * In some case, even when the driver supports lower rate, we still
314 * wish to receive a certain number of samples per seconds for various
315 * reasons (calibration, filtering, no change in power consumption...).
320 if (!sensor_get_fl_prop(s, "min_freq", &min_freq))
327 float sensor_get_max_freq (int s)
331 if (!sensor_get_fl_prop(s, "max_freq", &max_freq))
334 return ANDROID_MAX_FREQ;
337 int sensor_get_cal_steps (int s)
340 if (!sensor_get_prop(s, "cal_steps", &cal_steps))
346 float sensor_get_resolution (int s)
348 if (sensor[s].is_virtual) {
349 switch (sensor[s].type) {
350 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
351 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
352 return sensor[sensor[s].base[0]].resolution;
359 if (sensor[s].resolution != 0.0 ||
360 !sensor_get_fl_prop(s, "resolution", &sensor[s].resolution)) {
361 return sensor[s].resolution;
364 sensor[s].resolution = sensor[s].scale;
365 if (!sensor[s].resolution && sensor[s].num_channels)
366 sensor[s].resolution = sensor[s].channel[0].scale;
368 if (sensor[s].type == SENSOR_TYPE_MAGNETIC_FIELD)
369 sensor[s].resolution = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].resolution);
371 return sensor[s].resolution ? : 1;
375 float sensor_get_power (int s)
378 if (sensor[s].is_virtual) {
379 switch (sensor[s].type) {
380 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
381 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
382 return sensor[sensor[s].base[0]].power;
389 /* mA used while sensor is in use ; not sure about volts :) */
390 if (sensor[s].power != 0.0 ||
391 !sensor_get_fl_prop(s, "power", &sensor[s].power))
392 return sensor[s].power;
398 float sensor_get_illumincalib (int s)
400 /* calibrating the ALS Sensor*/
401 if (sensor[s].illumincalib != 0.0 ||
402 !sensor_get_fl_prop(s, "illumincalib", &sensor[s].illumincalib)) {
403 return sensor[s].illumincalib;
410 uint32_t sensor_get_quirks (int s)
412 char quirks_buf[MAX_NAME_SIZE];
414 /* Read and decode quirks property on first reference */
415 if (!(sensor[s].quirks & QUIRK_ALREADY_DECODED)) {
416 quirks_buf[0] = '\0';
417 sensor_get_st_prop(s, "quirks", quirks_buf);
419 if (strstr(quirks_buf, "init-rate"))
420 sensor[s].quirks |= QUIRK_INITIAL_RATE;
422 if (strstr(quirks_buf, "continuous"))
423 sensor[s].quirks |= QUIRK_FORCE_CONTINUOUS;
425 if (strstr(quirks_buf, "terse"))
426 sensor[s].quirks |= QUIRK_TERSE_DRIVER;
428 if (strstr(quirks_buf, "noisy"))
429 sensor[s].quirks |= QUIRK_NOISY;
431 if (strstr(quirks_buf, "biased"))
432 sensor[s].quirks |= QUIRK_BIASED;
434 if (strstr(quirks_buf, "spotty"))
435 sensor[s].quirks |= QUIRK_SPOTTY;
437 if (strstr(quirks_buf, "no-event"))
438 sensor[s].quirks |= QUIRK_NO_EVENT_MODE;
440 if (strstr(quirks_buf, "no-trig"))
441 sensor[s].quirks |= QUIRK_NO_TRIG_MODE;
443 if (strstr(quirks_buf, "no-poll"))
444 sensor[s].quirks |= QUIRK_NO_POLL_MODE;
446 if (strstr(quirks_buf, "hrtimer"))
447 sensor[s].quirks |= QUIRK_HRTIMER;
449 if (strstr(quirks_buf, "secondary"))
450 sensor[s].quirks |= QUIRK_SECONDARY;
452 sensor[s].quirks |= QUIRK_ALREADY_DECODED;
455 return sensor[s].quirks;
459 int sensor_get_order (int s, unsigned char map[MAX_CHANNELS])
461 char buf[MAX_NAME_SIZE];
463 int count = sensor_catalog[sensor[s].catalog_index].num_channels;
465 if (sensor_get_st_prop(s, "order", buf))
466 return 0; /* No order property */
468 /* Assume ASCII characters, in the '0'..'9' range */
470 for (i=0; i<count; i++)
471 if (buf[i] - '0' >= count) {
472 ALOGE("Order index out of range for sensor %d\n", s);
476 for (i=0; i<count; i++)
477 map[i] = buf[i] - '0';
479 return 1; /* OK to use modified ordering map */
482 int sensor_get_available_frequencies (int s)
484 int dev_num = sensor[s].dev_num, err, i;
485 const char *prefix = sensor_catalog[sensor[s].catalog_index].tag;
486 char avail_sysfs_path[PATH_MAX], freqs_buf[100];
490 sensor[s].avail_freqs_count = 0;
491 sensor[s].avail_freqs = 0;
493 sprintf(avail_sysfs_path, DEVICE_AVAIL_FREQ_PATH, dev_num);
495 err = sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf));
497 sprintf(avail_sysfs_path, SENSOR_AVAIL_FREQ_PATH, dev_num, prefix);
498 err = sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf));
503 for (p = freqs_buf, f = strtof(p, &end); p != end; p = end, f = strtof(p, &end))
504 sensor[s].avail_freqs_count++;
506 if (sensor[s].avail_freqs_count) {
507 sensor[s].avail_freqs = (float*) calloc(sensor[s].avail_freqs_count, sizeof(float));
509 for (p = freqs_buf, f = strtof(p, &end), i = 0; p != end; p = end, f = strtof(p, &end), i++)
510 sensor[s].avail_freqs[i] = f;
516 int sensor_get_mounting_matrix (int s, float mm[9])
518 int dev_num = sensor[s].dev_num, err, i;
519 char mm_path[PATH_MAX], mm_buf[100];
520 char *tmp1 = mm_buf, *tmp2;
522 switch (sensor[s].type) {
523 case SENSOR_TYPE_ACCELEROMETER:
524 case SENSOR_TYPE_MAGNETIC_FIELD:
525 case SENSOR_TYPE_GYROSCOPE:
526 case SENSOR_TYPE_PROXIMITY:
532 sprintf(mm_path, MOUNTING_MATRIX_PATH, dev_num);
534 err = sysfs_read_str(mm_path, mm_buf, sizeof(mm_buf));
538 for(i = 0; i < 9; i++) {
541 f = strtof(tmp1, &tmp2);
542 if (!f && tmp1 == tmp2)
549 * For proximity sensors, interpret a negative final z value as a hint that the sensor is back mounted. In that case, mark the sensor as secondary to
550 * ensure that it gets listed after other sensors of same type that would be front-mounted. Most applications will only ask for the default proximity
551 * sensor and it makes more sense to point to, say, the IR based proximity sensor rather than SAR based one if we have both, as on SoFIA LTE MRD boards.
553 if (sensor[s].type == SENSOR_TYPE_PROXIMITY) {
555 sensor[s].quirks |= QUIRK_SECONDARY;
560 ALOGI("%s: %f %f %f %f %f %f %f %f %f\n", __func__, mm[0], mm[1], mm[2], mm[3], mm[4], mm[5], mm[6], mm[7], mm[8]);
565 char* sensor_get_string_type (int s)
567 switch (sensor_desc[s].type) {
568 case SENSOR_TYPE_ACCELEROMETER:
569 return SENSOR_STRING_TYPE_ACCELEROMETER;
571 case SENSOR_TYPE_MAGNETIC_FIELD:
572 return SENSOR_STRING_TYPE_MAGNETIC_FIELD;
574 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
575 return SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
577 case SENSOR_TYPE_ORIENTATION:
578 return SENSOR_STRING_TYPE_ORIENTATION;
580 case SENSOR_TYPE_GYROSCOPE:
581 return SENSOR_STRING_TYPE_GYROSCOPE;
583 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
584 return SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
586 case SENSOR_TYPE_LIGHT:
587 return SENSOR_STRING_TYPE_LIGHT;
589 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
590 return SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
592 case SENSOR_TYPE_TEMPERATURE:
593 return SENSOR_STRING_TYPE_TEMPERATURE;
595 case SENSOR_TYPE_PROXIMITY:
596 return SENSOR_STRING_TYPE_PROXIMITY;
598 case SENSOR_TYPE_PRESSURE:
599 return SENSOR_STRING_TYPE_PRESSURE;
601 case SENSOR_TYPE_RELATIVE_HUMIDITY:
602 return SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
610 flag_t sensor_get_flags (int s)
614 switch (sensor_desc[s].type) {
615 case SENSOR_TYPE_LIGHT:
616 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
617 case SENSOR_TYPE_TEMPERATURE:
618 case SENSOR_TYPE_RELATIVE_HUMIDITY:
619 case SENSOR_TYPE_STEP_COUNTER:
620 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
624 case SENSOR_TYPE_PROXIMITY:
625 flags |= SENSOR_FLAG_WAKE_UP;
626 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
628 case SENSOR_TYPE_STEP_DETECTOR:
629 flags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
638 static int get_cdd_freq (int s, int must)
640 switch (sensor_desc[s].type) {
641 case SENSOR_TYPE_ACCELEROMETER:
642 return (must ? 100 : 200); /* must 100 Hz, should 200 Hz, CDD compliant */
644 case SENSOR_TYPE_GYROSCOPE:
645 return (must ? 200 : 200); /* must 200 Hz, should 200 Hz, CDD compliant */
647 case SENSOR_TYPE_MAGNETIC_FIELD:
648 return (must ? 10 : 50); /* must 10 Hz, should 50 Hz, CDD compliant */
650 case SENSOR_TYPE_LIGHT:
651 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
652 case SENSOR_TYPE_TEMPERATURE:
653 return (must ? 1 : 2); /* must 1 Hz, should 2Hz, not mentioned in CDD */
656 return 1; /* Use 1 Hz by default, e.g. for proximity */
661 * This value is defined only for continuous mode and on-change sensors. It is the delay between two sensor events corresponding to the lowest frequency that
662 * this sensor supports. When lower frequencies are requested through batch()/setDelay() the events will be generated at this frequency instead. It can be used
663 * by the framework or applications to estimate when the batch FIFO may be full. maxDelay should always fit within a 32 bit signed integer. It is declared as
664 * 64 bit on 64 bit architectures only for binary compatibility reasons. Availability: SENSORS_DEVICE_API_VERSION_1_3
666 max_delay_t sensor_get_max_delay (int s)
669 float min_supported_rate;
673 * continuous, on-change: maximum sampling period allowed in microseconds.
674 * one-shot, special : 0
676 switch (REPORTING_MODE(sensor_desc[s].flags)) {
677 case SENSOR_FLAG_ONE_SHOT_MODE:
678 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
681 case SENSOR_FLAG_ON_CHANGE_MODE:
682 return MAX_ON_CHANGE_SAMPLING_PERIOD_US;
688 if (sensor[s].is_virtual) {
689 switch (sensor[s].type) {
690 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
691 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
692 return sensor_desc[sensor[s].base[0]].maxDelay;
698 switch (sensor[s].mode) {
700 /* For interrupt-based devices, obey the list of supported sampling rates */
701 if (sensor[s].avail_freqs_count) {
702 min_supported_rate = 1000;
703 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
704 if (sensor[s].avail_freqs[i] < min_supported_rate)
705 min_supported_rate = sensor[s].avail_freqs[i];
709 /* Fall through ... */
713 min_supported_rate = 1;
717 /* Check if a minimum rate was specified for this sensor */
718 rate_cap = sensor_get_min_freq(s);
720 if (min_supported_rate < rate_cap)
721 min_supported_rate = rate_cap;
723 /* return 0 for wrong values */
724 if (min_supported_rate < 0.1)
727 /* Return microseconds */
728 return (max_delay_t) (1000000.0 / min_supported_rate);
731 float sensor_get_max_static_freq(int s)
733 float max_from_prop = sensor_get_max_freq(s);
735 /* If we have max specified via a property use it */
736 if (max_from_prop != ANDROID_MAX_FREQ) {
737 return max_from_prop;
739 /* The should rate */
740 return get_cdd_freq(s, 0);
744 int32_t sensor_get_min_delay (int s)
747 float max_supported_rate = 0;
748 float max_from_prop = sensor_get_max_freq(s);
750 /* continuous, on change: minimum sampling period allowed in microseconds.
751 * special : 0, unless otherwise noted
754 switch (REPORTING_MODE(sensor_desc[s].flags)) {
755 case SENSOR_FLAG_ON_CHANGE_MODE:
756 return MIN_ON_CHANGE_SAMPLING_PERIOD_US;
758 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
761 case SENSOR_FLAG_ONE_SHOT_MODE:
768 if (sensor[s].is_virtual) {
769 switch (sensor[s].type) {
770 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
771 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
772 return sensor_desc[sensor[s].base[0]].minDelay;
778 if (!sensor[s].avail_freqs_count) {
779 if (sensor[s].mode == MODE_POLL) {
780 /* If we have max specified via a property use it */
781 if (max_from_prop != ANDROID_MAX_FREQ)
782 max_supported_rate = max_from_prop;
784 /* The should rate */
785 max_supported_rate = get_cdd_freq(s, 0);
788 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
789 if (sensor[s].avail_freqs[i] > max_supported_rate &&
790 sensor[s].avail_freqs[i] <= max_from_prop) {
791 max_supported_rate = sensor[s].avail_freqs[i];
796 /* return 0 for wrong values */
797 if (max_supported_rate < 0.1)
800 /* Return microseconds */
801 return (int32_t) (1000000.0 / max_supported_rate);