OSDN Git Service

34297201c699d4d513bb849e847dd24ad13df280
[android-x86/hardware-libsensors.git] / hdaps.c
1 /**
2  * HDAPS accelerometer sensor
3  *
4  * Copyright (C) 2011 The Android-x86 Open Source Project
5  *
6  * by Stefan Seidel <stefans@android-x86.org>
7  *
8  * Licensed under GPLv2 or later
9  *
10  **/
11
12 #define LOG_TAG "HdapsSensors"
13
14 #include <stdint.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <math.h>
23 #include <poll.h>
24 #include <pthread.h>
25 #include <linux/input.h>
26
27 #include <cutils/atomic.h>
28 #include <cutils/log.h>
29 #include <hardware/sensors.h>
30
31 //#define DEBUG_SENSOR          1
32
33 #define CONVERT                 (GRAVITY_EARTH / 156.0f)
34 #define SENSOR_NAME             "hdaps"
35 #define INPUT_DIR               "/dev/input"
36 #define ARRAY_SIZE(a)           (sizeof(a) / sizeof(a[0]))
37 #define ID_ACCELERATION         (SENSORS_HANDLE_BASE + 0)
38
39 #define AMIN(a,b)               (((a)<(fabs(b)))?(a):(b))
40 #define SQUARE(x)               ((x)*(x))
41 #define COS_ASIN(m,x)           (sqrt(SQUARE(m)-SQUARE(AMIN(m,x))))
42 #define COS_ASIN_2D(m,x,y)      (COS_ASIN(m,x)*COS_ASIN(m,y)/(m))
43
44 static unsigned int forced_delay = 0;
45
46 struct sensors_poll_context_t {
47         struct sensors_poll_device_t device;
48         int fd;
49 };
50
51 static int common__close(struct hw_device_t *dev) {
52         struct sensors_poll_context_t *ctx = (struct sensors_poll_context_t *) dev;
53         if (ctx) {
54                 free(ctx);
55         }
56
57         return 0;
58 }
59
60 static int device__activate(struct sensors_poll_device_t *dev, int handle,
61                 int enabled) {
62
63         return 0;
64 }
65
66 static int device__set_delay(struct sensors_poll_device_t *device, int handle,
67                 int64_t ns) {
68         forced_delay = ns / 1000;
69         return 0;
70
71 }
72
73 static int device__poll(struct sensors_poll_device_t *device,
74                 sensors_event_t* data, int count) {
75
76         struct input_event event;
77         int ret;
78         struct sensors_poll_context_t *dev =
79                         (struct sensors_poll_context_t *) device;
80
81         if (dev->fd < 0)
82                 return 0;
83
84         while (1) {
85
86                 ret = read(dev->fd, &event, sizeof(event));
87
88 #ifdef DEBUG_SENSOR
89                 ALOGD("hdaps event %d - %d - %d\n", event.type, event.code, event.value);
90 #endif
91                 if (event.type == EV_ABS) {
92                         switch (event.code) {
93                         // Even though this mapping results in wrong results with some apps,
94                         // it just means that these apps are broken, i.e. they rely on the
95                         // fact that phone have portrait displays. Laptops/tablets however
96                         // have landscape displays, and the axes are relative to the default
97                         // screen orientation, not relative to portrait orientation.
98                         // See the nVidia Tegra accelerometer docs if you want to know for sure.
99                         case ABS_X:
100                                 data->acceleration.x = (float) event.value * CONVERT;
101                                 break;
102                         case ABS_Y:
103                                 // we invert the y-axis here because we assume the laptop is
104                                 // in tablet mode (and thus the display is rotated 180 degrees.
105                                 data->acceleration.y = -(float) event.value * CONVERT;
106                                 break;
107                         }
108                 } else if (event.type == EV_SYN) {
109                         data->timestamp = (int64_t) ((int64_t) event.time.tv_sec
110                                         * 1000000000 + (int64_t) event.time.tv_usec * 1000);
111                         // hdaps doesn't have z-axis, so simulate it by rotation matrix solution
112                         data ->acceleration.z = COS_ASIN_2D(GRAVITY_EARTH, data->acceleration.x, data->acceleration.y);
113                         data->sensor = ID_ACCELERATION;
114                         data->type = SENSOR_TYPE_ACCELEROMETER;
115                         data->acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
116                         // spare the CPU if desired
117                         if (forced_delay)
118                                 usleep(forced_delay);
119                         return 1;
120                 }
121         }
122
123         return -errno;
124 }
125
126 static int open_input_device(void) {
127         char *filename;
128         int fd;
129         DIR *dir;
130         struct dirent *de;
131         char name[80];
132         char devname[256];
133         dir = opendir(INPUT_DIR);
134         if (dir == NULL)
135                 return -1;
136
137         strcpy(devname, INPUT_DIR);
138         filename = devname + strlen(devname);
139         *filename++ = '/';
140
141         while ((de = readdir(dir))) {
142                 if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
143                         continue;
144                 strcpy(filename, de->d_name);
145                 fd = open(devname, O_RDONLY);
146                 if (fd < 0) {
147                         continue;
148                 }
149
150                 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
151                         name[0] = '\0';
152                 }
153
154                 if (!strcmp(name, SENSOR_NAME)) {
155 #ifdef DEBUG_SENSOR
156                         ALOGI("devname is %s \n", devname);
157 #endif
158                 } else {
159                         close(fd);
160                         continue;
161                 }
162                 closedir(dir);
163
164                 return fd;
165
166         }
167         closedir(dir);
168
169         return -1;
170 }
171
172 static const struct sensor_t sSensorList[] = {
173         {       .name = "HDAPS accelerometer",
174                 .vendor = "Linux kernel",
175                 .version = 1,
176                 .handle = ID_ACCELERATION,
177                 .type = SENSOR_TYPE_ACCELEROMETER,
178                 .maxRange = (GRAVITY_EARTH * 6.0f),
179                 .resolution = (GRAVITY_EARTH * 6.0f) / 1024.0f,
180                 .power = 0.84f,
181                 .reserved = {},
182         },
183 };
184
185 static int open_sensors(const struct hw_module_t* module, const char* name,
186                 struct hw_device_t** device);
187
188 static int sensors__get_sensors_list(struct sensors_module_t* module,
189                 struct sensor_t const** list) {
190         *list = sSensorList;
191
192         return ARRAY_SIZE(sSensorList);
193 }
194
195 static struct hw_module_methods_t sensors_module_methods = {
196                 .open = open_sensors };
197
198 struct sensors_module_t HAL_MODULE_INFO_SYM = {
199         .common = {
200                 .tag = HARDWARE_MODULE_TAG,
201                 .version_major = 1,
202                 .version_minor = 1,
203                 .id = SENSORS_HARDWARE_MODULE_ID,
204                 .name = "hdaps accelerometer sensor",
205                 .author = "Stefan Seidel",
206                 .methods = &sensors_module_methods,
207                 .dso = NULL,
208                 .reserved = {},
209         },
210         .get_sensors_list = sensors__get_sensors_list
211 };
212
213 static int open_sensors(const struct hw_module_t* module, const char* name,
214                 struct hw_device_t** device) {
215         int status = -EINVAL;
216
217         struct sensors_poll_context_t *dev = malloc(
218                         sizeof(struct sensors_poll_context_t));
219         memset(&dev->device, 0, sizeof(struct sensors_poll_device_t));
220
221         dev->device.common.tag = HARDWARE_DEVICE_TAG;
222         dev->device.common.version = 0;
223         dev->device.common.module = (struct hw_module_t*) module;
224         dev->device.common.close = common__close;
225         dev->device.activate = device__activate;
226         dev->device.setDelay = device__set_delay;
227         dev->device.poll = device__poll;
228
229         if ((dev->fd = open_input_device()) < 0) {
230                 ALOGE("g sensor get class path error \n");
231         } else {
232                 *device = &dev->device.common;
233                 status = 0;
234         }
235
236         return status;
237 }