blob: c3c295199e2b2aaa5a7a5cd422c639d5fb8d21a1 [file] [log] [blame]
Vincent Becker022224f2012-08-10 14:40:49 +02001/*
2 * Copyright (C) 2013 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 <hardware/vibrator.h>
18#include <hardware/hardware.h>
19
20#include <cutils/log.h>
21
Elliott Hughes07c08552015-01-29 21:19:10 -080022#include <malloc.h>
Vincent Becker022224f2012-08-10 14:40:49 +020023#include <stdio.h>
Rob Herring61701df2015-11-16 12:54:30 -060024#include <stdbool.h>
25#include <string.h>
Vincent Becker022224f2012-08-10 14:40:49 +020026#include <unistd.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <math.h>
30
Rob Herring61701df2015-11-16 12:54:30 -060031#define TIMEOUT_STR_LEN 20
32
Vincent Becker022224f2012-08-10 14:40:49 +020033static const char THE_DEVICE[] = "/sys/class/timed_output/vibrator/enable";
34
35static int vibra_exists() {
36 int fd;
37
38 fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));
39 if(fd < 0) {
Vincent Becker022224f2012-08-10 14:40:49 +020040 return 0;
41 }
42
43 close(fd);
44 return 1;
45}
46
Rob Herring61701df2015-11-16 12:54:30 -060047static int write_value(const char *file, const char *value)
Vincent Becker022224f2012-08-10 14:40:49 +020048{
49 int to_write, written, ret, fd;
50
Rob Herring61701df2015-11-16 12:54:30 -060051 fd = TEMP_FAILURE_RETRY(open(file, O_WRONLY));
52 if (fd < 0) {
Vincent Becker022224f2012-08-10 14:40:49 +020053 return -errno;
54 }
55
Rob Herring61701df2015-11-16 12:54:30 -060056 to_write = strlen(value) + 1;
Vincent Becker022224f2012-08-10 14:40:49 +020057 written = TEMP_FAILURE_RETRY(write(fd, value, to_write));
Vincent Becker022224f2012-08-10 14:40:49 +020058 if (written == -1) {
59 ret = -errno;
60 } else if (written != to_write) {
61 /* even though EAGAIN is an errno value that could be set
62 by write() in some cases, none of them apply here. So, this return
63 value can be clearly identified when debugging and suggests the
Rob Herring61701df2015-11-16 12:54:30 -060064 caller that it may try to call vibrator_on() again */
Vincent Becker022224f2012-08-10 14:40:49 +020065 ret = -EAGAIN;
66 } else {
67 ret = 0;
68 }
69
70 errno = 0;
71 close(fd);
72
73 return ret;
74}
75
Rob Herring61701df2015-11-16 12:54:30 -060076static int sendit(unsigned int timeout_ms)
77{
78 char value[TIMEOUT_STR_LEN]; /* large enough for millions of years */
79
80 snprintf(value, sizeof(value), "%u", timeout_ms);
81 return write_value(THE_DEVICE, value);
82}
83
Vincent Becker022224f2012-08-10 14:40:49 +020084static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
85{
86 /* constant on, up to maximum allowed time */
87 return sendit(timeout_ms);
88}
89
90static int vibra_off(vibrator_device_t* vibradev __unused)
91{
92 return sendit(0);
93}
94
Rob Herring61701df2015-11-16 12:54:30 -060095static const char LED_DEVICE[] = "/sys/class/leds/vibrator";
96
97static int write_led_file(const char *file, const char *value)
98{
99 char file_str[50];
100
101 snprintf(file_str, sizeof(file_str), "%s/%s", LED_DEVICE, file);
102 return write_value(file_str, value);
103}
104
105static int vibra_led_exists()
106{
107 return !write_led_file("trigger", "transient");
108}
109
110static int vibra_led_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
111{
112 int ret;
113 char value[TIMEOUT_STR_LEN]; /* large enough for millions of years */
114
115 ret = write_led_file("state", "1");
116 if (ret)
117 return ret;
118
119 snprintf(value, sizeof(value), "%u\n", timeout_ms);
120 ret = write_led_file("duration", value);
121 if (ret)
122 return ret;
123
124 return write_led_file("activate", "1");
125}
126
127static int vibra_led_off(vibrator_device_t* vibradev __unused)
128{
129 return write_led_file("activate", "0");
130}
131
Vincent Becker022224f2012-08-10 14:40:49 +0200132static int vibra_close(hw_device_t *device)
133{
134 free(device);
135 return 0;
136}
137
138static int vibra_open(const hw_module_t* module, const char* id __unused,
139 hw_device_t** device __unused) {
Rob Herring61701df2015-11-16 12:54:30 -0600140 bool use_led;
141
142 if (vibra_exists()) {
143 ALOGD("Vibrator using timed_output");
144 use_led = false;
145 } else if (vibra_led_exists()) {
146 ALOGD("Vibrator using LED trigger");
147 use_led = true;
148 } else {
Vincent Becker022224f2012-08-10 14:40:49 +0200149 ALOGE("Vibrator device does not exist. Cannot start vibrator");
150 return -ENODEV;
151 }
152
153 vibrator_device_t *vibradev = calloc(1, sizeof(vibrator_device_t));
154
155 if (!vibradev) {
156 ALOGE("Can not allocate memory for the vibrator device");
157 return -ENOMEM;
158 }
159
160 vibradev->common.tag = HARDWARE_DEVICE_TAG;
161 vibradev->common.module = (hw_module_t *) module;
162 vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);
163 vibradev->common.close = vibra_close;
164
Rob Herring61701df2015-11-16 12:54:30 -0600165 if (use_led) {
166 vibradev->vibrator_on = vibra_led_on;
167 vibradev->vibrator_off = vibra_led_off;
168 } else {
169 vibradev->vibrator_on = vibra_on;
170 vibradev->vibrator_off = vibra_off;
171 }
Vincent Becker022224f2012-08-10 14:40:49 +0200172
173 *device = (hw_device_t *) vibradev;
174
175 return 0;
176}
177
178/*===========================================================================*/
179/* Default vibrator HW module interface definition */
180/*===========================================================================*/
181
182static struct hw_module_methods_t vibrator_module_methods = {
183 .open = vibra_open,
184};
185
186struct hw_module_t HAL_MODULE_INFO_SYM = {
187 .tag = HARDWARE_MODULE_TAG,
188 .module_api_version = VIBRATOR_API_VERSION,
189 .hal_api_version = HARDWARE_HAL_API_VERSION,
190 .id = VIBRATOR_HARDWARE_MODULE_ID,
191 .name = "Default vibrator HAL",
192 .author = "The Android Open Source Project",
193 .methods = &vibrator_module_methods,
194};