f6bb4d29274ba65d8e73f537cb734db461d50342
[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_play_internal(feedback_pattern_internal_e pattern)
344 {
345         int err;
346         bool result;
347         int switched;
348
349         /* check initialize */
350         pthread_mutex_lock(&fmutex);
351         if (!init_cnt) {
352                 _E("Not initialized"); //LCOV_EXCL_LINE
353                 pthread_mutex_unlock(&fmutex);
354                 return FEEDBACK_ERROR_NOT_INITIALIZED;
355         }
356         pthread_mutex_unlock(&fmutex);
357
358         if (pattern <= FEEDBACK_PATTERN_NONE ||
359             pattern >= profile->max_pattern) {
360                 _E("Invalid parameter : pattern(%d)", pattern);
361                 return FEEDBACK_ERROR_INVALID_PARAMETER;
362         }
363
364         /* if you need to switch pattern */
365         if (profile->get_switched_pattern) {
366                 result = profile->get_switched_pattern(pattern, &switched);
367                 if (result) {
368                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
369                                         profile->str_pattern(pattern), profile->str_pattern(switched));
370                         pattern = switched;
371                 }
372         }
373
374         /* play all device */
375         err = devices_play(pattern);
376         /**
377          * devices_play() returns error even if all devices are failed.
378          * It means if to play anything is successful,
379          * this function regards as success.
380          */
381         if (err == -ENOTSUP)
382                 return FEEDBACK_ERROR_NOT_SUPPORTED;
383         else if (err < 0)
384                 return FEEDBACK_ERROR_OPERATION_FAILED;
385
386         return FEEDBACK_ERROR_NONE;
387 }
388
389 API int feedback_play_type_internal(feedback_type_e type, feedback_pattern_internal_e pattern)
390 {
391         const struct device_ops *dev;
392         int err;
393         bool result;
394         int switched;
395
396         /* check initialize */
397         pthread_mutex_lock(&fmutex);
398         if (!init_cnt) {
399                 _E("Not initialized"); //LCOV_EXCL_LINE
400                 pthread_mutex_unlock(&fmutex);
401                 return FEEDBACK_ERROR_NOT_INITIALIZED;
402         }
403         pthread_mutex_unlock(&fmutex);
404
405         if (type <= FEEDBACK_TYPE_NONE ||
406             type >= profile->max_type) {
407                 _E("Invalid parameter : type(%d)", type);
408                 return FEEDBACK_ERROR_INVALID_PARAMETER;
409         }
410
411         if (pattern <= FEEDBACK_PATTERN_INTERNAL_NONE ||
412             pattern >= profile->max_pattern) {
413                 _E("Invalid parameter : pattern(%d)", pattern);
414                 return FEEDBACK_ERROR_INVALID_PARAMETER;
415         }
416
417         /* if you need to switch pattern */
418         if (profile->get_switched_pattern) {
419                 result = profile->get_switched_pattern(pattern, &switched);
420                 if (result) {
421                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
422                                         profile->str_pattern(pattern), profile->str_pattern(switched));
423                         pattern = switched;
424                 }
425         }
426
427         /* play proper device */
428         dev = find_device(type);
429         if (!dev) {
430                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
431                 return FEEDBACK_ERROR_NOT_SUPPORTED;
432         }
433
434         err = dev->play(pattern);
435         if (err == -ENOTSUP)
436                 return FEEDBACK_ERROR_NOT_SUPPORTED;
437         else if (err == -ECOMM || err == -EACCES)
438                 return FEEDBACK_ERROR_PERMISSION_DENIED;
439         else if (err < 0)
440                 return FEEDBACK_ERROR_OPERATION_FAILED;
441
442         return FEEDBACK_ERROR_NONE;
443 }
444
445 API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
446 {
447         const struct device_ops *dev;
448         char buf[PATH_MAX] = {0,};
449         int err;
450
451         if (path == NULL) {
452                 _E("Invalid parameter : path(NULL)");
453                 return FEEDBACK_ERROR_INVALID_PARAMETER;
454         }
455
456         if (type <= FEEDBACK_TYPE_NONE ||
457             type >= profile->max_type) {
458                 _E("Invalid parameter : type(%d)", type);
459                 return FEEDBACK_ERROR_INVALID_PARAMETER;
460         }
461
462         if (type == FEEDBACK_TYPE_VIBRATION)
463                 return FEEDBACK_ERROR_NOT_SUPPORTED;
464
465         if (pattern <= FEEDBACK_PATTERN_NONE ||
466             pattern >= profile->max_pattern) {
467                 _E("Invalid parameter : pattern(%d)", pattern);
468                 return FEEDBACK_ERROR_INVALID_PARAMETER;
469         }
470
471         /* proper device get path */
472         dev = find_device(type);
473         if (dev) {
474                 err = dev->get_path(pattern, buf, sizeof(buf));
475                 if (err < 0)
476                         return FEEDBACK_ERROR_OPERATION_FAILED;
477         }
478
479         *path = strdup(buf);
480         return FEEDBACK_ERROR_NONE;
481 }
482
483 API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
484 {
485         const struct device_ops *dev;
486         int err;
487
488         if (type <= FEEDBACK_TYPE_NONE ||
489             type >= profile->max_type) {
490                 _E("Invalid parameter : type(%d)", type);
491                 return FEEDBACK_ERROR_INVALID_PARAMETER;
492         }
493
494         if (pattern <= FEEDBACK_PATTERN_NONE ||
495             pattern >= profile->max_pattern) {
496                 _E("Invalid parameter : pattern(%d)", pattern);
497                 return FEEDBACK_ERROR_INVALID_PARAMETER;
498         }
499
500         if (type == FEEDBACK_TYPE_VIBRATION) {
501                 _E("Not supported type"); //LCOV_EXCL_LINE
502                 return FEEDBACK_ERROR_NOT_SUPPORTED;
503         }
504
505         /* proper device set path */
506         dev = find_device(type);
507         if (dev) {
508                 err = dev->set_path(pattern, path);
509                 if (err < 0)
510                         return FEEDBACK_ERROR_OPERATION_FAILED;
511         }
512
513         return FEEDBACK_ERROR_NONE;
514 }