Remove feedback-ids-internal.h from rootstrap
[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 "feedback-ids-internal.h"
26 #include "profiles.h"
27 #include "devices.h"
28 #include "log.h"
29 #include "dbus.h"
30
31 #ifndef API
32 #define API __attribute__ ((visibility("default")))
33 #endif
34
35 static unsigned int init_cnt;
36 static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
37
38 static int restart_callback()
39 {
40         const struct device_ops *dev;
41
42         dev = find_device(FEEDBACK_TYPE_VIBRATION);
43         if (!dev) {
44                 _E("Not supported device : type(FEEDBACK_TYPE_VIBRATION)"); //LCOV_EXCL_LINE
45                 return -1;
46         }
47         if (dev->init)
48                 dev->init();
49         return 0;
50 }
51
52 API int feedback_initialize(void)
53 {
54         int ret;
55
56         pthread_mutex_lock(&fmutex);
57         if (!profile) {
58                 _E("there is no valid profile module."); //LCOV_EXCL_LINE
59                 pthread_mutex_unlock(&fmutex);
60                 return FEEDBACK_ERROR_NOT_SUPPORTED;
61         }
62
63         if (init_cnt++ > 0) {
64                 pthread_mutex_unlock(&fmutex);
65                 return FEEDBACK_ERROR_NONE;
66         }
67
68         ret = register_signal_handler(restart_callback);
69         if (ret < 0)
70                 _E("Fail to register signal handler: %d", ret);
71
72         /* initialize device */
73         devices_init();
74
75         /* initialize profile feature */
76         if (profile->init)
77                 profile->init();
78
79         pthread_mutex_unlock(&fmutex);
80         return FEEDBACK_ERROR_NONE;
81 }
82
83 API int feedback_deinitialize(void)
84 {
85         int ret;
86
87         pthread_mutex_lock(&fmutex);
88         if (!init_cnt) {
89                 pthread_mutex_unlock(&fmutex);
90                 return FEEDBACK_ERROR_NOT_INITIALIZED;
91         }
92
93         if (init_cnt-- > 1) {
94                 pthread_mutex_unlock(&fmutex);
95                 return FEEDBACK_ERROR_NONE;
96         }
97
98         ret = unregister_signal_handler(restart_callback);
99         if (ret < 0)
100                 _E("Fail to unregister signal handler: %d", ret);
101
102         /* deinitialize device */
103         devices_exit();
104
105         /* deinitialize profile feature */
106         if (profile->exit)
107                 profile->exit();
108
109         pthread_mutex_unlock(&fmutex);
110         return FEEDBACK_ERROR_NONE;
111 }
112
113 API int feedback_play(feedback_pattern_e pattern)
114 {
115         int err;
116         bool result;
117         int switched;
118
119         /* check initialize */
120         pthread_mutex_lock(&fmutex);
121         if (!init_cnt) {
122                 _E("Not initialized"); //LCOV_EXCL_LINE
123                 pthread_mutex_unlock(&fmutex);
124                 return FEEDBACK_ERROR_NOT_INITIALIZED;
125         }
126         pthread_mutex_unlock(&fmutex);
127
128         if (pattern <= FEEDBACK_PATTERN_NONE ||
129             pattern >= profile->max_pattern) {
130                 _E("Invalid parameter : pattern(%d)", pattern);
131                 return FEEDBACK_ERROR_INVALID_PARAMETER;
132         }
133
134         /* if you need to switch pattern */
135         if (profile->get_switched_pattern) {
136                 result = profile->get_switched_pattern(pattern, &switched);
137                 if (result) {
138                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
139                                         profile->str_pattern(pattern), profile->str_pattern(switched));
140                         pattern = switched;
141                 }
142         }
143
144         /* play all device */
145         err = devices_play(pattern);
146         /**
147          * devices_play() returns error even if all devices are failed.
148          * It means if to play anything is successful,
149          * this function regards as success.
150          */
151         if (err == -ENOTSUP)
152                 return FEEDBACK_ERROR_NOT_SUPPORTED;
153         else if (err < 0)
154                 return FEEDBACK_ERROR_OPERATION_FAILED;
155
156         return FEEDBACK_ERROR_NONE;
157 }
158
159 API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
160 {
161         const struct device_ops *dev;
162         int err;
163         bool result;
164         int switched;
165
166         /* check initialize */
167         pthread_mutex_lock(&fmutex);
168         if (!init_cnt) {
169                 _E("Not initialized"); //LCOV_EXCL_LINE
170                 pthread_mutex_unlock(&fmutex);
171                 return FEEDBACK_ERROR_NOT_INITIALIZED;
172         }
173         pthread_mutex_unlock(&fmutex);
174
175         if (type <= FEEDBACK_TYPE_NONE ||
176             type >= profile->max_type) {
177                 _E("Invalid parameter : type(%d)", type);
178                 return FEEDBACK_ERROR_INVALID_PARAMETER;
179         }
180
181         if (pattern <= FEEDBACK_PATTERN_NONE ||
182             pattern >= profile->max_pattern) {
183                 _E("Invalid parameter : pattern(%d)", pattern);
184                 return FEEDBACK_ERROR_INVALID_PARAMETER;
185         }
186
187         /* if you need to switch pattern */
188         if (profile->get_switched_pattern) {
189                 result = profile->get_switched_pattern(pattern, &switched);
190                 if (result) {
191                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
192                                         profile->str_pattern(pattern), profile->str_pattern(switched));
193                         pattern = switched;
194                 }
195         }
196
197         /* play proper device */
198         dev = find_device(type);
199         if (!dev) {
200                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
201                 return FEEDBACK_ERROR_NOT_SUPPORTED;
202         }
203
204         err = dev->play(pattern);
205         if (err == -ENOTSUP)
206                 return FEEDBACK_ERROR_NOT_SUPPORTED;
207         else if (err == -ECOMM || err == -EACCES)
208                 return FEEDBACK_ERROR_PERMISSION_DENIED;
209         else if (err < 0)
210                 return FEEDBACK_ERROR_OPERATION_FAILED;
211
212         return FEEDBACK_ERROR_NONE;
213 }
214
215 API int feedback_stop(void)
216 {
217         int err;
218
219         /* check initialize */
220         pthread_mutex_lock(&fmutex);
221         if (!init_cnt) {
222                 _E("Not initialized"); //LCOV_EXCL_LINE
223                 pthread_mutex_unlock(&fmutex);
224                 return FEEDBACK_ERROR_NOT_INITIALIZED;
225         }
226         pthread_mutex_unlock(&fmutex);
227
228         /* stop all device */
229         err = devices_stop();
230         if (err == -ENOTSUP)
231                 return FEEDBACK_ERROR_NOT_SUPPORTED;
232         else if (err == -ECOMM || err == -EACCES)
233                 return FEEDBACK_ERROR_PERMISSION_DENIED;
234         else if (err < 0)
235                 return FEEDBACK_ERROR_OPERATION_FAILED;
236
237         return FEEDBACK_ERROR_NONE;
238 }
239
240 API int feedback_is_supported_pattern(feedback_type_e type, feedback_pattern_e pattern, bool *status)
241 {
242         const struct device_ops *dev;
243         bool supported;
244         int err;
245         bool result;
246         int switched;
247
248         /* check initialize */
249         pthread_mutex_lock(&fmutex);
250         if (!init_cnt) {
251                 _E("Not initialized"); //LCOV_EXCL_LINE
252                 pthread_mutex_unlock(&fmutex);
253                 return FEEDBACK_ERROR_NOT_INITIALIZED;
254         }
255         pthread_mutex_unlock(&fmutex);
256
257         if (!status) {
258                 _E("Invalid parameter : status(NULL)");
259                 return FEEDBACK_ERROR_INVALID_PARAMETER;
260         }
261
262         if (type <= FEEDBACK_TYPE_NONE ||
263             type >= profile->max_type) {
264                 _E("Invalid parameter : type(%d)", type);
265                 return FEEDBACK_ERROR_INVALID_PARAMETER;
266         }
267
268         if (pattern <= FEEDBACK_PATTERN_NONE ||
269             pattern >= profile->max_pattern) {
270                 _E("Invalid parameter : pattern(%d)", pattern);
271                 return FEEDBACK_ERROR_INVALID_PARAMETER;
272         }
273
274         /* if you need to switch pattern */
275         if (profile->get_switched_pattern) {
276                 result = profile->get_switched_pattern(pattern, &switched);
277                 if (result) {
278                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
279                                         profile->str_pattern(pattern), profile->str_pattern(switched));
280                         pattern = switched;
281                 }
282         }
283
284         /* play proper device */
285         dev = find_device(type);
286         if (!dev) {
287                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
288                 return FEEDBACK_ERROR_NOT_SUPPORTED;
289         }
290
291         err = dev->is_supported(pattern, &supported);
292         if (err == -ENOTSUP)
293                 return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error
294         else if (err == -ECOMM || err == -EACCES)
295                 return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE System Error
296         else if (err < 0) {
297                 _E("fail to invoke is_supported() : pattern(%d)", pattern); //LCOV_EXCL_LINE
298                 return FEEDBACK_ERROR_OPERATION_FAILED;
299         }
300
301         *status = supported;
302
303         return FEEDBACK_ERROR_NONE;
304 }
305
306 /* Internal APIs */
307 API int feedback_play_type_by_name(char *type, char *pattern)
308 {
309         feedback_type_e etype;
310         feedback_pattern_e epattern;
311         int type_max;
312         int pattern_max;
313
314         if (!type || !pattern) {
315                 _E("Invalid parameter : type(%x), pattern(%x)", type, pattern);
316                 return FEEDBACK_ERROR_INVALID_PARAMETER;
317         }
318
319         type_max = profile->max_type;
320         for (etype = 0; etype < type_max; ++etype) {
321                 if (!strncmp(type, profile->str_type[etype], strlen(type)))
322                         break;
323         }
324
325         if (etype == type_max) {
326                 _E("Invalid parameter : type(%s)", type);
327                 return FEEDBACK_ERROR_INVALID_PARAMETER;
328         }
329
330         pattern_max = profile->max_pattern;
331         for (epattern = 0; epattern < pattern_max; ++epattern) {
332                 if (!strncmp(pattern, profile->str_pattern(epattern), strlen(pattern)))
333                         break;
334         }
335
336         if (epattern == pattern_max) {
337                 _E("Invalid parameter : pattern(%s)", pattern);
338                 return FEEDBACK_ERROR_INVALID_PARAMETER;
339         }
340
341         return feedback_play_type(etype, epattern);
342 }
343
344 API int feedback_play_internal(feedback_pattern_internal_e pattern)
345 {
346         int err;
347         bool result;
348         int switched;
349
350         /* check initialize */
351         pthread_mutex_lock(&fmutex);
352         if (!init_cnt) {
353                 _E("Not initialized"); //LCOV_EXCL_LINE
354                 pthread_mutex_unlock(&fmutex);
355                 return FEEDBACK_ERROR_NOT_INITIALIZED;
356         }
357         pthread_mutex_unlock(&fmutex);
358
359         if (pattern <= FEEDBACK_PATTERN_NONE ||
360             pattern >= profile->max_pattern) {
361                 _E("Invalid parameter : pattern(%d)", pattern);
362                 return FEEDBACK_ERROR_INVALID_PARAMETER;
363         }
364
365         /* if you need to switch pattern */
366         if (profile->get_switched_pattern) {
367                 result = profile->get_switched_pattern(pattern, &switched);
368                 if (result) {
369                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
370                                         profile->str_pattern(pattern), profile->str_pattern(switched));
371                         pattern = switched;
372                 }
373         }
374
375         /* play all device */
376         err = devices_play(pattern);
377         /**
378          * devices_play() returns error even if all devices are failed.
379          * It means if to play anything is successful,
380          * this function regards as success.
381          */
382         if (err == -ENOTSUP)
383                 return FEEDBACK_ERROR_NOT_SUPPORTED;
384         else if (err < 0)
385                 return FEEDBACK_ERROR_OPERATION_FAILED;
386
387         return FEEDBACK_ERROR_NONE;
388 }
389
390 API int feedback_play_type_internal(feedback_type_e type, feedback_pattern_internal_e pattern)
391 {
392         const struct device_ops *dev;
393         int err;
394         bool result;
395         int switched;
396
397         /* check initialize */
398         pthread_mutex_lock(&fmutex);
399         if (!init_cnt) {
400                 _E("Not initialized"); //LCOV_EXCL_LINE
401                 pthread_mutex_unlock(&fmutex);
402                 return FEEDBACK_ERROR_NOT_INITIALIZED;
403         }
404         pthread_mutex_unlock(&fmutex);
405
406         if (type <= FEEDBACK_TYPE_NONE ||
407             type >= profile->max_type) {
408                 _E("Invalid parameter : type(%d)", type);
409                 return FEEDBACK_ERROR_INVALID_PARAMETER;
410         }
411
412         if (pattern <= FEEDBACK_PATTERN_INTERNAL_NONE ||
413             pattern >= profile->max_pattern) {
414                 _E("Invalid parameter : pattern(%d)", pattern);
415                 return FEEDBACK_ERROR_INVALID_PARAMETER;
416         }
417
418         /* if you need to switch pattern */
419         if (profile->get_switched_pattern) {
420                 result = profile->get_switched_pattern(pattern, &switched);
421                 if (result) {
422                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
423                                         profile->str_pattern(pattern), profile->str_pattern(switched));
424                         pattern = switched;
425                 }
426         }
427
428         /* play proper device */
429         dev = find_device(type);
430         if (!dev) {
431                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
432                 return FEEDBACK_ERROR_NOT_SUPPORTED;
433         }
434
435         err = dev->play(pattern);
436         if (err == -ENOTSUP)
437                 return FEEDBACK_ERROR_NOT_SUPPORTED;
438         else if (err == -ECOMM || err == -EACCES)
439                 return FEEDBACK_ERROR_PERMISSION_DENIED;
440         else if (err < 0)
441                 return FEEDBACK_ERROR_OPERATION_FAILED;
442
443         return FEEDBACK_ERROR_NONE;
444 }
445
446 API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
447 {
448         const struct device_ops *dev;
449         char buf[PATH_MAX] = {0,};
450         int err;
451
452         if (path == NULL) {
453                 _E("Invalid parameter : path(NULL)");
454                 return FEEDBACK_ERROR_INVALID_PARAMETER;
455         }
456
457         if (type <= FEEDBACK_TYPE_NONE ||
458             type >= profile->max_type) {
459                 _E("Invalid parameter : type(%d)", type);
460                 return FEEDBACK_ERROR_INVALID_PARAMETER;
461         }
462
463         if (type == FEEDBACK_TYPE_VIBRATION)
464                 return FEEDBACK_ERROR_NOT_SUPPORTED;
465
466         if (pattern <= FEEDBACK_PATTERN_NONE ||
467             pattern >= profile->max_pattern) {
468                 _E("Invalid parameter : pattern(%d)", pattern);
469                 return FEEDBACK_ERROR_INVALID_PARAMETER;
470         }
471
472         /* proper device get path */
473         dev = find_device(type);
474         if (dev) {
475                 err = dev->get_path(pattern, buf, sizeof(buf));
476                 if (err < 0)
477                         return FEEDBACK_ERROR_OPERATION_FAILED;
478         }
479
480         *path = strdup(buf);
481         return FEEDBACK_ERROR_NONE;
482 }
483
484 API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
485 {
486         const struct device_ops *dev;
487         int err;
488
489         if (type <= FEEDBACK_TYPE_NONE ||
490             type >= profile->max_type) {
491                 _E("Invalid parameter : type(%d)", type);
492                 return FEEDBACK_ERROR_INVALID_PARAMETER;
493         }
494
495         if (pattern <= FEEDBACK_PATTERN_NONE ||
496             pattern >= profile->max_pattern) {
497                 _E("Invalid parameter : pattern(%d)", pattern);
498                 return FEEDBACK_ERROR_INVALID_PARAMETER;
499         }
500
501         if (type == FEEDBACK_TYPE_VIBRATION) {
502                 _E("Not supported type"); //LCOV_EXCL_LINE
503                 return FEEDBACK_ERROR_NOT_SUPPORTED;
504         }
505
506         /* proper device set path */
507         dev = find_device(type);
508         if (dev) {
509                 err = dev->set_path(pattern, path);
510                 if (err < 0)
511                         return FEEDBACK_ERROR_OPERATION_FAILED;
512         }
513
514         return FEEDBACK_ERROR_NONE;
515 }