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