Support feedback internal enums for each profile
[platform/core/system/libsvi.git] / src / feedback.c
1 /*
2  * libfeedback
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18
19 #include <stdio.h>
20 #include <stdbool.h>
21 #include <string.h>
22 #include <limits.h>
23
24 #include "feedback.h"
25 #include "profiles.h"
26 #include "devices.h"
27 #include "log.h"
28 #include "dbus.h"
29
30 #ifndef API
31 #define API __attribute__ ((visibility("default")))
32 #endif
33
34 static unsigned int init_cnt;
35 static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
36
37 static int restart_callback()
38 {
39         const struct device_ops *dev;
40
41         dev = find_device(FEEDBACK_TYPE_VIBRATION);
42         if (!dev) {
43                 _E("Not supported device : type(FEEDBACK_TYPE_VIBRATION)"); //LCOV_EXCL_LINE
44                 return -1;
45         }
46         if (dev->init)
47                 dev->init();
48         return 0;
49 }
50
51 API int feedback_initialize(void)
52 {
53         int ret;
54
55         pthread_mutex_lock(&fmutex);
56         if (!profile) {
57                 _E("there is no valid profile module."); //LCOV_EXCL_LINE
58                 pthread_mutex_unlock(&fmutex);
59                 return FEEDBACK_ERROR_NOT_SUPPORTED;
60         }
61
62         if (init_cnt++ > 0) {
63                 pthread_mutex_unlock(&fmutex);
64                 return FEEDBACK_ERROR_NONE;
65         }
66
67         ret = register_signal_handler(restart_callback);
68         if (ret < 0)
69                 _E("Fail to register signal handler: %d", ret);
70
71         /* initialize device */
72         devices_init();
73
74         /* initialize profile feature */
75         if (profile->init)
76                 profile->init();
77
78         pthread_mutex_unlock(&fmutex);
79         return FEEDBACK_ERROR_NONE;
80 }
81
82 API int feedback_deinitialize(void)
83 {
84         int ret;
85
86         pthread_mutex_lock(&fmutex);
87         if (!init_cnt) {
88                 pthread_mutex_unlock(&fmutex);
89                 return FEEDBACK_ERROR_NOT_INITIALIZED;
90         }
91
92         if (init_cnt-- > 1) {
93                 pthread_mutex_unlock(&fmutex);
94                 return FEEDBACK_ERROR_NONE;
95         }
96
97         ret = unregister_signal_handler(restart_callback);
98         if (ret < 0)
99                 _E("Fail to unregister signal handler: %d", ret);
100
101         /* deinitialize device */
102         devices_exit();
103
104         /* deinitialize profile feature */
105         if (profile->exit)
106                 profile->exit();
107
108         pthread_mutex_unlock(&fmutex);
109         return FEEDBACK_ERROR_NONE;
110 }
111
112 API int feedback_play(feedback_pattern_e pattern)
113 {
114         int err;
115         bool result;
116         int switched;
117
118         /* check initialize */
119         pthread_mutex_lock(&fmutex);
120         if (!init_cnt) {
121                 _E("Not initialized"); //LCOV_EXCL_LINE
122                 pthread_mutex_unlock(&fmutex);
123                 return FEEDBACK_ERROR_NOT_INITIALIZED;
124         }
125         pthread_mutex_unlock(&fmutex);
126
127         if (pattern <= FEEDBACK_PATTERN_NONE ||
128             pattern >= profile->max_pattern) {
129                 _E("Invalid parameter : pattern(%d)", pattern);
130                 return FEEDBACK_ERROR_INVALID_PARAMETER;
131         }
132
133         /* if you need to switch pattern */
134         if (profile->get_switched_pattern) {
135                 result = profile->get_switched_pattern(pattern, &switched);
136                 if (result) {
137                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
138                                         profile->str_pattern(pattern), profile->str_pattern(switched));
139                         pattern = switched;
140                 }
141         }
142
143         /* play all device */
144         err = devices_play(pattern);
145         /**
146          * devices_play() returns error even if all devices are failed.
147          * It means if to play anything is successful,
148          * this function regards as success.
149          */
150         if (err == -ENOTSUP)
151                 return FEEDBACK_ERROR_NOT_SUPPORTED;
152         else if (err < 0)
153                 return FEEDBACK_ERROR_OPERATION_FAILED;
154
155         return FEEDBACK_ERROR_NONE;
156 }
157
158 API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
159 {
160         const struct device_ops *dev;
161         int err;
162         bool result;
163         int switched;
164
165         /* check initialize */
166         pthread_mutex_lock(&fmutex);
167         if (!init_cnt) {
168                 _E("Not initialized"); //LCOV_EXCL_LINE
169                 pthread_mutex_unlock(&fmutex);
170                 return FEEDBACK_ERROR_NOT_INITIALIZED;
171         }
172         pthread_mutex_unlock(&fmutex);
173
174         if (type <= FEEDBACK_TYPE_NONE ||
175             type >= profile->max_type) {
176                 _E("Invalid parameter : type(%d)", type);
177                 return FEEDBACK_ERROR_INVALID_PARAMETER;
178         }
179
180         if (pattern <= FEEDBACK_PATTERN_NONE ||
181             pattern >= profile->max_pattern) {
182                 _E("Invalid parameter : pattern(%d)", pattern);
183                 return FEEDBACK_ERROR_INVALID_PARAMETER;
184         }
185
186         /* if you need to switch pattern */
187         if (profile->get_switched_pattern) {
188                 result = profile->get_switched_pattern(pattern, &switched);
189                 if (result) {
190                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
191                                         profile->str_pattern(pattern), profile->str_pattern(switched));
192                         pattern = switched;
193                 }
194         }
195
196         /* play proper device */
197         dev = find_device(type);
198         if (!dev) {
199                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
200                 return FEEDBACK_ERROR_NOT_SUPPORTED;
201         }
202
203         err = dev->play(pattern);
204         if (err == -ENOTSUP)
205                 return FEEDBACK_ERROR_NOT_SUPPORTED;
206         else if (err == -ECOMM || err == -EACCES)
207                 return FEEDBACK_ERROR_PERMISSION_DENIED;
208         else if (err < 0)
209                 return FEEDBACK_ERROR_OPERATION_FAILED;
210
211         return FEEDBACK_ERROR_NONE;
212 }
213
214 API int feedback_stop(void)
215 {
216         int err;
217
218         /* check initialize */
219         pthread_mutex_lock(&fmutex);
220         if (!init_cnt) {
221                 _E("Not initialized"); //LCOV_EXCL_LINE
222                 pthread_mutex_unlock(&fmutex);
223                 return FEEDBACK_ERROR_NOT_INITIALIZED;
224         }
225         pthread_mutex_unlock(&fmutex);
226
227         /* stop all device */
228         err = devices_stop();
229         if (err == -ENOTSUP)
230                 return FEEDBACK_ERROR_NOT_SUPPORTED;
231         else if (err == -ECOMM || err == -EACCES)
232                 return FEEDBACK_ERROR_PERMISSION_DENIED;
233         else if (err < 0)
234                 return FEEDBACK_ERROR_OPERATION_FAILED;
235
236         return FEEDBACK_ERROR_NONE;
237 }
238
239 API int feedback_is_supported_pattern(feedback_type_e type, feedback_pattern_e pattern, bool *status)
240 {
241         const struct device_ops *dev;
242         bool supported;
243         int err;
244         bool result;
245         int switched;
246
247         /* check initialize */
248         pthread_mutex_lock(&fmutex);
249         if (!init_cnt) {
250                 _E("Not initialized"); //LCOV_EXCL_LINE
251                 pthread_mutex_unlock(&fmutex);
252                 return FEEDBACK_ERROR_NOT_INITIALIZED;
253         }
254         pthread_mutex_unlock(&fmutex);
255
256         if (!status) {
257                 _E("Invalid parameter : status(NULL)");
258                 return FEEDBACK_ERROR_INVALID_PARAMETER;
259         }
260
261         if (type <= FEEDBACK_TYPE_NONE ||
262             type >= profile->max_type) {
263                 _E("Invalid parameter : type(%d)", type);
264                 return FEEDBACK_ERROR_INVALID_PARAMETER;
265         }
266
267         if (pattern <= FEEDBACK_PATTERN_NONE ||
268             pattern >= profile->max_pattern) {
269                 _E("Invalid parameter : pattern(%d)", pattern);
270                 return FEEDBACK_ERROR_INVALID_PARAMETER;
271         }
272
273         /* if you need to switch pattern */
274         if (profile->get_switched_pattern) {
275                 result = profile->get_switched_pattern(pattern, &switched);
276                 if (result) {
277                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
278                                         profile->str_pattern(pattern), profile->str_pattern(switched));
279                         pattern = switched;
280                 }
281         }
282
283         /* play proper device */
284         dev = find_device(type);
285         if (!dev) {
286                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
287                 return FEEDBACK_ERROR_NOT_SUPPORTED;
288         }
289
290         err = dev->is_supported(pattern, &supported);
291         if (err == -ENOTSUP)
292                 return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error
293         else if (err == -ECOMM || err == -EACCES)
294                 return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE System Error
295         else if (err < 0) {
296                 _E("fail to invoke is_supported() : pattern(%d)", pattern); //LCOV_EXCL_LINE
297                 return FEEDBACK_ERROR_OPERATION_FAILED;
298         }
299
300         *status = supported;
301
302         return FEEDBACK_ERROR_NONE;
303 }
304
305 /* Internal APIs */
306 API int feedback_play_type_by_name(char *type, char *pattern)
307 {
308         feedback_type_e etype;
309         feedback_pattern_e epattern;
310         int type_max;
311         int pattern_max;
312
313         if (!type || !pattern) {
314                 _E("Invalid parameter : type(%x), pattern(%x)", type, pattern);
315                 return FEEDBACK_ERROR_INVALID_PARAMETER;
316         }
317
318         type_max = profile->max_type;
319         for (etype = 0; etype < type_max; ++etype) {
320                 if (!strncmp(type, profile->str_type[etype], strlen(type)))
321                         break;
322         }
323
324         if (etype == type_max) {
325                 _E("Invalid parameter : type(%s)", type);
326                 return FEEDBACK_ERROR_INVALID_PARAMETER;
327         }
328
329         pattern_max = profile->max_pattern;
330         for (epattern = 0; epattern < pattern_max; ++epattern) {
331                 if (!strncmp(pattern, profile->str_pattern(epattern), strlen(pattern)))
332                         break;
333         }
334
335         if (epattern == pattern_max) {
336                 _E("Invalid parameter : pattern(%s)", pattern);
337                 return FEEDBACK_ERROR_INVALID_PARAMETER;
338         }
339
340         return feedback_play_type(etype, epattern);
341 }
342
343 API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
344 {
345         const struct device_ops *dev;
346         char buf[PATH_MAX] = {0,};
347         int err;
348
349         if (path == NULL) {
350                 _E("Invalid parameter : path(NULL)");
351                 return FEEDBACK_ERROR_INVALID_PARAMETER;
352         }
353
354         if (type <= FEEDBACK_TYPE_NONE ||
355             type >= profile->max_type) {
356                 _E("Invalid parameter : type(%d)", type);
357                 return FEEDBACK_ERROR_INVALID_PARAMETER;
358         }
359
360         if (type == FEEDBACK_TYPE_VIBRATION)
361                 return FEEDBACK_ERROR_NOT_SUPPORTED;
362
363         if (pattern <= FEEDBACK_PATTERN_NONE ||
364             pattern >= profile->max_pattern) {
365                 _E("Invalid parameter : pattern(%d)", pattern);
366                 return FEEDBACK_ERROR_INVALID_PARAMETER;
367         }
368
369         /* proper device get path */
370         dev = find_device(type);
371         if (dev) {
372                 err = dev->get_path(pattern, buf, sizeof(buf));
373                 if (err < 0)
374                         return FEEDBACK_ERROR_OPERATION_FAILED;
375         }
376
377         *path = strdup(buf);
378         return FEEDBACK_ERROR_NONE;
379 }
380
381 API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
382 {
383         const struct device_ops *dev;
384         int err;
385
386         if (type <= FEEDBACK_TYPE_NONE ||
387             type >= profile->max_type) {
388                 _E("Invalid parameter : type(%d)", type);
389                 return FEEDBACK_ERROR_INVALID_PARAMETER;
390         }
391
392         if (pattern <= FEEDBACK_PATTERN_NONE ||
393             pattern >= profile->max_pattern) {
394                 _E("Invalid parameter : pattern(%d)", pattern);
395                 return FEEDBACK_ERROR_INVALID_PARAMETER;
396         }
397
398         if (type == FEEDBACK_TYPE_VIBRATION) {
399                 _E("Not supported type"); //LCOV_EXCL_LINE
400                 return FEEDBACK_ERROR_NOT_SUPPORTED;
401         }
402
403         /* proper device set path */
404         dev = find_device(type);
405         if (dev) {
406                 err = dev->set_path(pattern, path);
407                 if (err < 0)
408                         return FEEDBACK_ERROR_OPERATION_FAILED;
409         }
410
411         return FEEDBACK_ERROR_NONE;
412 }