OSDN Git Service

Min/Max delay for Light and Temperature
[android-x86/hardware-intel-libsensors.git] / enumeration.c
index 92fa713..eda8845 100644 (file)
@@ -14,6 +14,7 @@
 #include "description.h"
 #include "control.h"
 #include "calibration.h"
+#include "filtering.h"
 
 /*
  * This table maps syfs entries in scan_elements directories to sensor types,
@@ -44,6 +45,10 @@ struct sensor_catalog_entry_t sensor_catalog[] = {
 
 #define CATALOG_SIZE   ARRAY_SIZE(sensor_catalog)
 
+/* ACPI PLD (physical location of device) definitions, as used with sensors */
+
+#define PANEL_FRONT    4
+#define PANEL_BACK     5
 
 /* We equate sensor handles to indices in these tables */
 
@@ -52,6 +57,149 @@ struct sensor_info_t sensor_info[MAX_SENSORS];      /* Internal descriptors      */
 int sensor_count;                              /* Detected sensors          */
 
 
+static void setup_properties_from_pld(int s, int panel, int rotation,
+                                     int num_channels)
+{
+       /*
+        * Generate suitable order and opt_scale directives from the PLD panel
+        * and rotation codes we got. This can later be superseded by the usual
+        * properties if necessary. Eventually we'll need to replace these
+        * mechanisms by a less convoluted one, such as a 3x3 placement matrix.
+        */
+
+       int x = 1;
+       int y = 1;
+       int z = 1;
+       int xy_swap = 0;
+       int angle = rotation * 45;
+
+       /* Only deal with 3 axis chips for now */
+       if (num_channels < 3)
+               return;
+
+       if (panel == PANEL_BACK) {
+               /* Chip placed on the back panel ; negate x and z */
+               x = -x;
+               z = -z;
+       }
+
+       switch (angle) {
+               case 90: /* 90° clockwise: negate y then swap x,y */
+                       xy_swap = 1;
+                       y = -y;
+                       break;
+
+               case 180: /* Upside down: negate x and y */
+                       x = -x;
+                       y = -y;
+                       break;
+
+               case 270: /* 90° counter clockwise: negate x then swap x,y */
+                       x = -x;
+                       xy_swap = 1;
+                       break;
+       }
+
+       if (xy_swap) {
+               sensor_info[s].order[0] = 1;
+               sensor_info[s].order[1] = 0;
+               sensor_info[s].order[2] = 2;
+               sensor_info[s].quirks |= QUIRK_FIELD_ORDERING;
+       }
+
+       sensor_info[s].channel[0].opt_scale = x;
+       sensor_info[s].channel[1].opt_scale = y;
+       sensor_info[s].channel[2].opt_scale = z;
+}
+
+
+static int is_valid_pld (int panel, int rotation)
+{
+       if (panel != PANEL_FRONT && panel != PANEL_BACK) {
+               ALOGW("Unhandled PLD panel spec: %d\n", panel);
+               return 0;
+       }
+
+       /* Only deal with 90° rotations for now */
+       if (rotation < 0 || rotation > 7 || (rotation & 1)) {
+               ALOGW("Unhandled PLD rotation spec: %d\n", rotation);
+               return 0;
+       }
+
+       return 1;
+}
+
+
+static int read_pld_from_properties (int s, int* panel, int* rotation)
+{
+       int p, r;
+
+       if (sensor_get_prop(s, "panel", &p))
+               return -1;
+
+       if (sensor_get_prop(s, "rotation", &r))
+               return -1;
+
+       if (!is_valid_pld(p, r))
+               return -1;
+
+       *panel = p;
+       *rotation = r;
+
+       ALOGI("S%d PLD from properties: panel=%d, rotation=%d\n", s, p, r);
+
+       return 0;
+}
+
+
+static int read_pld_from_sysfs (int s, int dev_num, int* panel, int* rotation)
+{
+       char sysfs_path[PATH_MAX];
+       int p,r;
+
+       sprintf(sysfs_path, BASE_PATH "../firmware_node/pld/panel", dev_num);
+
+       if (sysfs_read_int(sysfs_path, &p))
+               return -1;
+
+       sprintf(sysfs_path, BASE_PATH "../firmware_node/pld/rotation", dev_num);
+
+       if (sysfs_read_int(sysfs_path, &r))
+               return -1;
+
+       if (!is_valid_pld(p, r))
+               return -1;
+
+       *panel = p;
+       *rotation = r;
+
+       ALOGI("S%d PLD from sysfs: panel=%d, rotation=%d\n", s, p, r);
+
+       return 0;
+}
+
+
+static void decode_placement_information (int dev_num, int num_channels, int s)
+{
+       /*
+        * See if we have optional "physical location of device" ACPI tags.
+        * We're only interested in panel and rotation specifiers. Use the
+        * .panel and .rotation properties in priority, and the actual ACPI
+        * values as a second source.
+        */
+
+       int panel;
+       int rotation;
+
+       if (read_pld_from_properties(s, &panel, &rotation) &&
+               read_pld_from_sysfs(s, dev_num, &panel, &rotation))
+                       return; /* No PLD data available */
+
+       /* Map that to field ordering and scaling mechanisms */
+       setup_properties_from_pld(s, panel, rotation, num_channels);
+}
+
+
 static void add_sensor (int dev_num, int catalog_index, int use_polling)
 {
        int s;
@@ -84,11 +232,12 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
        sensor_info[s].dev_num          = dev_num;
        sensor_info[s].catalog_index    = catalog_index;
 
+        num_channels = sensor_catalog[catalog_index].num_channels;
+
         if (use_polling)
                 sensor_info[s].num_channels = 0;
         else
-                sensor_info[s].num_channels =
-                                sensor_catalog[catalog_index].num_channels;
+                sensor_info[s].num_channels = num_channels;
 
        prefix = sensor_catalog[catalog_index].tag;
 
@@ -122,7 +271,7 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
                 sensor_info[s].scale = 1;
 
                 /* Read channel specific scale if any*/
-                for (c = 0; c < sensor_catalog[catalog_index].num_channels; c++)
+                for (c = 0; c < num_channels; c++)
                 {
                         sprintf(sysfs_path, BASE_PATH "%s", dev_num,
                            sensor_catalog[catalog_index].channel[c].scale_path);
@@ -138,6 +287,16 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
                 }
         }
 
+        /* Set default scaling - if num_channels is zero, we have one channel */
+
+       sensor_info[s].channel[0].opt_scale = 1;
+
+       for (c = 1; c < num_channels; c++)
+               sensor_info[s].channel[c].opt_scale = 1;
+
+       /* Read ACPI _PLD attributes for this sensor, if there are any */
+       decode_placement_information(dev_num, num_channels, s);
+
         /*
          * See if we have optional correction scaling factors for each of the
          * channels of this sensor. These would be expressed using properties
@@ -146,23 +305,17 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
          * for all types of sensors, and whatever transform is selected, on top
          * of any previous conversions.
          */
-        num_channels = sensor_catalog[catalog_index].num_channels;
 
         if (num_channels) {
                for (c = 0; c < num_channels; c++) {
-                       opt_scale = 1;
-
                        ch_name = sensor_catalog[catalog_index].channel[c].name;
                        sprintf(suffix, "%s.opt_scale", ch_name);
-                       sensor_get_fl_prop(s, suffix, &opt_scale);
-
-                       sensor_info[s].channel[c].opt_scale = opt_scale;
+                       if (!sensor_get_fl_prop(s, suffix, &opt_scale))
+                               sensor_info[s].channel[c].opt_scale = opt_scale;
                }
-        } else {
-               opt_scale = 1;
-               sensor_get_fl_prop(s, "opt_scale", &opt_scale);
-               sensor_info[s].channel[0].opt_scale = opt_scale;
-        }
+        } else
+               if (!sensor_get_fl_prop(s, "opt_scale", &opt_scale))
+                       sensor_info[s].channel[0].opt_scale = opt_scale;
 
        /* Initialize Android-visible descriptor */
        sensor_desc[s].name             = sensor_get_name(s);
@@ -180,7 +333,17 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
        */
        sensor_desc[s].requiredPermission = "";
        sensor_desc[s].flags = sensor_get_flags(s);
+       sensor_desc[s].minDelay = sensor_get_min_delay(s);
        sensor_desc[s].maxDelay = sensor_get_max_delay(s);
+       ALOGI("Sensor %d (%s) type(%d) minD(%ld) maxD(%ld) flags(%2.2x)\n",
+               s, sensor_info[s].friendly_name, sensor_desc[s].type,
+               sensor_desc[s].minDelay, sensor_desc[s].maxDelay, sensor_desc[s].flags);
+
+       /* We currently do not implement batching when we'll so
+        * these should be overriden appropriately
+        */
+       sensor_desc[s].fifoReservedEventCount = 0;
+       sensor_desc[s].fifoMaxEventCount = 0;
 
        if (sensor_info[s].internal_name[0] == '\0') {
                /*
@@ -192,13 +355,24 @@ static void add_sensor (int dev_num, int catalog_index, int use_polling)
                strcpy(sensor_info[s].internal_name, "(null)");
        }
 
-       if (sensor_catalog[catalog_index].type == SENSOR_TYPE_GYROSCOPE ||
-               sensor_catalog[catalog_index].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
+       if (sensor_type == SENSOR_TYPE_GYROSCOPE ||
+               sensor_type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
                struct gyro_cal* calibration_data = calloc(1, sizeof(struct gyro_cal));
                sensor_info[s].cal_data = calibration_data;
+               struct filter* f_data = (struct filter*) calloc(1, sizeof(struct filter));
+               f_data->x_buff = (struct circ_buff*) calloc(1, sizeof (struct circ_buff));
+               f_data->y_buff = (struct circ_buff*) calloc(1, sizeof (struct circ_buff));
+               f_data->z_buff = (struct circ_buff*) calloc(1, sizeof (struct circ_buff));
+               f_data->x_buff->buff = (float*)calloc(SAMPLE_SIZE, sizeof(float));
+               f_data->y_buff->buff = (float*)calloc(SAMPLE_SIZE, sizeof(float));
+               f_data->z_buff->buff = (float*)calloc(SAMPLE_SIZE, sizeof(float));
+               f_data->x_buff->size = SAMPLE_SIZE;
+               f_data->y_buff->size = SAMPLE_SIZE;
+               f_data->z_buff->size = SAMPLE_SIZE;
+               sensor_info[s].filter = f_data;
        }
 
-       if (sensor_catalog[catalog_index].type == SENSOR_TYPE_MAGNETIC_FIELD) {
+       if (sensor_type == SENSOR_TYPE_MAGNETIC_FIELD) {
                struct compass_cal* calibration_data = calloc(1, sizeof(struct compass_cal));
                sensor_info[s].cal_data = calibration_data;
        }
@@ -347,58 +521,65 @@ static void orientation_sensor_check(void)
                        }
 }
 
-static void uncalibrated_gyro_check (void)
+static int is_continuous (int s)
 {
-       unsigned int has_gyr = 0;
-       unsigned int dev_num;
-       int i, c;
-       unsigned int is_poll_sensor;
+       /* Is sensor s of the continous trigger type kind? */
 
-       int cal_idx = 0;
-       int uncal_idx = 0;
+       int catalog_index = sensor_info[s].catalog_index;
+       int sensor_type = sensor_catalog[catalog_index].type;
 
-       /* Checking to see if we have a gyroscope - we can only have uncal if we have the base sensor */
-       for (i=0; i < sensor_count; i++)
-               if(sensor_catalog[sensor_info[i].catalog_index].type == SENSOR_TYPE_GYROSCOPE)
-               {
-                       has_gyr=1;
-                       dev_num = sensor_info[i].dev_num;
-                       is_poll_sensor = !sensor_info[i].num_channels;
-                       cal_idx = i;
-                       break;
-               }
+       switch (sensor_type) {
+               case SENSOR_TYPE_ACCELEROMETER:
+               case SENSOR_TYPE_MAGNETIC_FIELD:
+               case SENSOR_TYPE_ORIENTATION:
+               case SENSOR_TYPE_GYROSCOPE:
+               case SENSOR_TYPE_PRESSURE:
+               case SENSOR_TYPE_GRAVITY:
+               case SENSOR_TYPE_LINEAR_ACCELERATION:
+               case SENSOR_TYPE_ROTATION_VECTOR:
+               case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+               case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+               case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                       return 1;
+
+               default:
+                       return 0;
+       }
+}
 
+
+static void propose_new_trigger (int s, char trigger_name[MAX_NAME_SIZE],
+                                int sensor_name_len)
+{
        /*
-        * If we have a gyro we can add the uncalibrated sensor of the same type and
-        * on the same dev_num. We will save indexes for easy finding and also save the
-        * channel specific information.
+        * A new trigger has been enumerated for this sensor. Check if it makes
+        * sense to use it over the currently selected one, and select it if it
+        * is so. The format is something like sensor_name-dev0.
         */
-       if (has_gyr)
-               for (i=0; i<CATALOG_SIZE; i++)
-                       if (sensor_catalog[i].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
-                               add_sensor(dev_num, i, is_poll_sensor);
 
-                               uncal_idx = sensor_count - 1; /* Just added uncalibrated sensor */
+       const char *suffix = trigger_name + sensor_name_len + 1;
 
-                               /* Similar to build_sensor_report_maps */
-                               for (c = 0; c < sensor_info[uncal_idx].num_channels; c++)
-                               {
-                                       memcpy( &(sensor_info[uncal_idx].channel[c].type_spec),
-                                               &(sensor_info[cal_idx].channel[c].type_spec),
-                                               sizeof(sensor_info[uncal_idx].channel[c].type_spec));
-                                       sensor_info[uncal_idx].channel[c].type_info = sensor_info[cal_idx].channel[c].type_info;
-                                       sensor_info[uncal_idx].channel[c].offset    = sensor_info[cal_idx].channel[c].offset;
-                                       sensor_info[uncal_idx].channel[c].size      = sensor_info[cal_idx].channel[c].size;
-                               }
-                               strncpy(sensor_info[uncal_idx].trigger_name,
-                                       sensor_info[cal_idx].trigger_name,
-                                       MAX_NAME_SIZE);
-                               sensor_info[uncal_idx].pair_idx = cal_idx;
-                               sensor_info[cal_idx].pair_idx = uncal_idx;
-                               break;
-                       }
+       /* dev is the default, and lowest priority; no need to update */
+       if (!memcmp(suffix, "dev", 3))
+               return;
+
+       /*
+        * If we found any-motion trigger, record it and force the sensor to
+        * automatic intermediate event generation mode, at least if it is of a
+        * continuously firing sensor type.
+        */
+
+       if (!memcmp(suffix, "any-motion-", 11) && is_continuous(s)) {
+               /* Update the any-motion trigger name to use for this sensor */
+               strcpy(sensor_info[s].motion_trigger_name, trigger_name);
+               return;
+       }
+
+       /* Update the initial trigger name to use for this sensor */
+       strcpy(sensor_info[s].init_trigger_name, trigger_name);
 }
 
+
 static void update_sensor_matching_trigger_name (char name[MAX_NAME_SIZE])
 {
        /*
@@ -413,6 +594,7 @@ static void update_sensor_matching_trigger_name (char name[MAX_NAME_SIZE])
        int dev_num;
        int len;
        char* cursor;
+       int sensor_name_len;
 
        /*
         * First determine the iio device number this trigger refers to. We
@@ -438,13 +620,16 @@ static void update_sensor_matching_trigger_name (char name[MAX_NAME_SIZE])
 
        /* See if that matches a sensor */
        for (s=0; s<sensor_count; s++)
-               if (sensor_info[s].dev_num == dev_num &&
-                       !strncmp(name, sensor_info[s].internal_name,
-                               strlen(sensor_info[s].internal_name))) {
-                               /* Update sensor structure and return */
-                               strcpy(sensor_info[s].trigger_name, name);
-                               return;
-                       }
+               if (sensor_info[s].dev_num == dev_num) {
+
+                       sensor_name_len = strlen(sensor_info[s].internal_name);
+
+                       if (!strncmp(name,
+                                    sensor_info[s].internal_name,
+                                    sensor_name_len))
+                               /* Switch to new trigger if appropriate */
+                               propose_new_trigger(s, name, sensor_name_len);
+               }
 }
 
 
@@ -459,8 +644,9 @@ static void setup_trigger_names (void)
 
        /* By default, use the name-dev convention that most drivers use */
        for (s=0; s<sensor_count; s++)
-               snprintf(sensor_info[s].trigger_name, MAX_NAME_SIZE, "%s-dev%d",
-                       sensor_info[s].internal_name, sensor_info[s].dev_num);
+               snprintf(sensor_info[s].init_trigger_name,
+                        MAX_NAME_SIZE, "%s-dev%d",
+                        sensor_info[s].internal_name, sensor_info[s].dev_num);
 
        /* Now have a look to /sys/bus/iio/devices/triggerX entries */
 
@@ -473,17 +659,84 @@ static void setup_trigger_names (void)
                if (ret < 0)
                        break;
 
+               /* Record initial and any-motion triggers names */
                update_sensor_matching_trigger_name(buf);
        }
 
        for (s=0; s<sensor_count; s++)
                if (sensor_info[s].num_channels) {
-                       ALOGI(  "Sensor %d (%s) using iio trigger %s\n", s,
+                       ALOGI(  "Sensor %d (%s) default trigger: %s\n", s,
                                sensor_info[s].friendly_name,
-                               sensor_info[s].trigger_name);
+                               sensor_info[s].init_trigger_name);
+                       if (sensor_info[s].motion_trigger_name[0])
+                               ALOGI(  "Sensor %d (%s) motion trigger: %s\n",
+                               s, sensor_info[s].friendly_name,
+                               sensor_info[s].motion_trigger_name);
                }
 }
 
+static void uncalibrated_gyro_check (void)
+{
+       unsigned int has_gyr = 0;
+       unsigned int dev_num;
+       int i, c;
+       unsigned int is_poll_sensor;
+       char buf[MAX_NAME_SIZE];
+
+       int cal_idx = 0;
+       int uncal_idx = 0;
+       int catalog_size = CATALOG_SIZE; /* Avoid GCC sign comparison warning */
+
+       /* Checking to see if we have a gyroscope - we can only have uncal if we have the base sensor */
+       for (i=0; i < sensor_count; i++)
+               if(sensor_catalog[sensor_info[i].catalog_index].type == SENSOR_TYPE_GYROSCOPE)
+               {
+                       has_gyr=1;
+                       dev_num = sensor_info[i].dev_num;
+                       is_poll_sensor = !sensor_info[i].num_channels;
+                       cal_idx = i;
+                       break;
+               }
+
+       /*
+        * If we have a gyro we can add the uncalibrated sensor of the same type and
+        * on the same dev_num. We will save indexes for easy finding and also save the
+        * channel specific information.
+        */
+       if (has_gyr)
+               for (i=0; i<catalog_size; i++)
+                       if (sensor_catalog[i].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
+                               add_sensor(dev_num, i, is_poll_sensor);
+
+                               uncal_idx = sensor_count - 1; /* Just added uncalibrated sensor */
+
+                               /* Similar to build_sensor_report_maps */
+                               for (c = 0; c < sensor_info[uncal_idx].num_channels; c++)
+                               {
+                                       memcpy( &(sensor_info[uncal_idx].channel[c].type_spec),
+                                               &(sensor_info[cal_idx].channel[c].type_spec),
+                                               sizeof(sensor_info[uncal_idx].channel[c].type_spec));
+                                       sensor_info[uncal_idx].channel[c].type_info = sensor_info[cal_idx].channel[c].type_info;
+                                       sensor_info[uncal_idx].channel[c].offset    = sensor_info[cal_idx].channel[c].offset;
+                                       sensor_info[uncal_idx].channel[c].size      = sensor_info[cal_idx].channel[c].size;
+                               }
+                               sensor_info[uncal_idx].pair_idx = cal_idx;
+                               sensor_info[cal_idx].pair_idx = uncal_idx;
+                               strncpy(sensor_info[uncal_idx].init_trigger_name,
+                                       sensor_info[cal_idx].init_trigger_name,
+                                       MAX_NAME_SIZE);
+                               strncpy(sensor_info[uncal_idx].motion_trigger_name,
+                                       sensor_info[cal_idx].motion_trigger_name,
+                                       MAX_NAME_SIZE);
+
+                               /* Add "Uncalibrated " prefix to sensor name */
+                               strcpy(buf, sensor_info[cal_idx].friendly_name);
+                               snprintf(sensor_info[uncal_idx].friendly_name,
+                                        MAX_NAME_SIZE,
+                                        "%s %s", "Uncalibrated", buf);
+                               break;
+                       }
+}
 
 void enumerate_sensors (void)
 {
@@ -528,8 +781,10 @@ void enumerate_sensors (void)
        /* Make sure Android fall backs to its own orientation sensor */
        orientation_sensor_check();
 
-       /* Create the uncalibrated counterpart to the compensated gyroscope;
-        * This is is a new sensor type in Android 4.4 */
+       /*
+        * Create the uncalibrated counterpart to the compensated gyroscope.
+        * This is is a new sensor type in Android 4.4.
+        */
        uncalibrated_gyro_check();
 }
 
@@ -541,14 +796,30 @@ void delete_enumeration_data (void)
        for (i = 0; i < sensor_count; i++)
        switch (sensor_catalog[sensor_info[i].catalog_index].type) {
                case SENSOR_TYPE_MAGNETIC_FIELD:
+                       if (sensor_info[i].cal_data != NULL) {
+                               free(sensor_info[i].cal_data);
+                               sensor_info[i].cal_data = NULL;
+                               sensor_info[i].cal_level = 0;
+                       }
+                       break;
                case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
                case SENSOR_TYPE_GYROSCOPE:
                        if (sensor_info[i].cal_data != NULL) {
                                free(sensor_info[i].cal_data);
                                sensor_info[i].cal_data = NULL;
-                               sensor_info[i].calibrated = 0;
+                               sensor_info[i].cal_level = 0;
                        }
                        break;
+                       if (sensor_info[i].filter != NULL) {
+                               free(((struct filter*)sensor_info[i].filter)->x_buff->buff);
+                               free(((struct filter*)sensor_info[i].filter)->y_buff->buff);
+                               free(((struct filter*)sensor_info[i].filter)->z_buff->buff);
+                               free(((struct filter*)sensor_info[i].filter)->x_buff);
+                               free(((struct filter*)sensor_info[i].filter)->y_buff);
+                               free(((struct filter*)sensor_info[i].filter)->z_buff);
+                               free(sensor_info[i].filter);
+                               sensor_info[i].filter = NULL;
+                       }
                default:
                        break;
        }