Add comments for line/function coverage analysis
[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
29 #ifndef API
30 #define API __attribute__ ((visibility("default")))
31 #endif
32
33 static unsigned int init_cnt;
34 static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
35
36 API int feedback_initialize(void)
37 {
38         pthread_mutex_lock(&fmutex);
39         if (!profile) {
40                 _E("there is no valid profile module."); //LCOV_EXCL_LINE
41                 pthread_mutex_unlock(&fmutex);
42                 return FEEDBACK_ERROR_NOT_SUPPORTED;
43         }
44
45         if (init_cnt++ > 0) {
46                 pthread_mutex_unlock(&fmutex);
47                 return FEEDBACK_ERROR_NONE;
48         }
49
50         /* initialize device */
51         devices_init();
52
53         /* initialize profile feature */
54         if (profile->init)
55                 profile->init();
56
57         pthread_mutex_unlock(&fmutex);
58         return FEEDBACK_ERROR_NONE;
59 }
60
61 API int feedback_deinitialize(void)
62 {
63         pthread_mutex_lock(&fmutex);
64         if (!init_cnt) {
65                 pthread_mutex_unlock(&fmutex);
66                 return FEEDBACK_ERROR_NOT_INITIALIZED;
67         }
68
69         if (init_cnt-- > 1) {
70                 pthread_mutex_unlock(&fmutex);
71                 return FEEDBACK_ERROR_NONE;
72         }
73
74         /* deinitialize device */
75         devices_exit();
76
77         /* deinitialize profile feature */
78         if (profile->exit)
79                 profile->exit();
80
81         pthread_mutex_unlock(&fmutex);
82         return FEEDBACK_ERROR_NONE;
83 }
84
85 API int feedback_play(feedback_pattern_e pattern)
86 {
87         int err;
88         bool result;
89         int switched;
90
91         /* check initialize */
92         pthread_mutex_lock(&fmutex);
93         if (!init_cnt) {
94                 _E("Not initialized"); //LCOV_EXCL_LINE
95                 pthread_mutex_unlock(&fmutex);
96                 return FEEDBACK_ERROR_NOT_INITIALIZED;
97         }
98         pthread_mutex_unlock(&fmutex);
99
100         if (pattern <= FEEDBACK_PATTERN_NONE ||
101             pattern >= profile->max_pattern) {
102                 _E("Invalid parameter : pattern(%d)", pattern);
103                 return FEEDBACK_ERROR_INVALID_PARAMETER;
104         }
105
106         /* if you need to switch pattern */
107         if (profile->get_switched_pattern) {
108                 result = profile->get_switched_pattern(pattern, &switched);
109                 if (result) {
110                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
111                                         profile->str_pattern[pattern], profile->str_pattern[switched]);
112                         pattern = switched;
113                 }
114         }
115
116         /* play all device */
117         err = devices_play(pattern);
118         /**
119          * devices_play() returns error even if all devices are failed.
120          * It means if to play anything is successful,
121          * this function regards as success.
122          */
123         if (err == -ENOTSUP)
124                 return FEEDBACK_ERROR_NOT_SUPPORTED;
125         else if (err < 0)
126                 return FEEDBACK_ERROR_OPERATION_FAILED;
127
128         return FEEDBACK_ERROR_NONE;
129 }
130
131 API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
132 {
133         const struct device_ops *dev;
134         int err;
135         bool result;
136         int switched;
137
138         /* check initialize */
139         pthread_mutex_lock(&fmutex);
140         if (!init_cnt) {
141                 _E("Not initialized"); //LCOV_EXCL_LINE
142                 pthread_mutex_unlock(&fmutex);
143                 return FEEDBACK_ERROR_NOT_INITIALIZED;
144         }
145         pthread_mutex_unlock(&fmutex);
146
147         if (type <= FEEDBACK_TYPE_NONE ||
148             type >= profile->max_type) {
149                 _E("Invalid parameter : type(%d)", type);
150                 return FEEDBACK_ERROR_INVALID_PARAMETER;
151         }
152
153         if (pattern <= FEEDBACK_PATTERN_NONE ||
154             pattern >= profile->max_pattern) {
155                 _E("Invalid parameter : pattern(%d)", pattern);
156                 return FEEDBACK_ERROR_INVALID_PARAMETER;
157         }
158
159         /* if you need to switch pattern */
160         if (profile->get_switched_pattern) {
161                 result = profile->get_switched_pattern(pattern, &switched);
162                 if (result) {
163                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
164                                         profile->str_pattern[pattern], profile->str_pattern[switched]);
165                         pattern = switched;
166                 }
167         }
168
169         /* play proper device */
170         dev = find_device(type);
171         if (!dev) {
172                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
173                 return FEEDBACK_ERROR_NOT_SUPPORTED;
174         }
175
176         err = dev->play(pattern);
177         if (err == -ENOTSUP)
178                 return FEEDBACK_ERROR_NOT_SUPPORTED;
179         else if (err == -ECOMM || err == -EACCES)
180                 return FEEDBACK_ERROR_PERMISSION_DENIED;
181         else if (err < 0)
182                 return FEEDBACK_ERROR_OPERATION_FAILED;
183
184         return FEEDBACK_ERROR_NONE;
185 }
186
187 API int feedback_stop(void)
188 {
189         int err;
190
191         /* check initialize */
192         pthread_mutex_lock(&fmutex);
193         if (!init_cnt) {
194                 _E("Not initialized"); //LCOV_EXCL_LINE
195                 pthread_mutex_unlock(&fmutex);
196                 return FEEDBACK_ERROR_NOT_INITIALIZED;
197         }
198         pthread_mutex_unlock(&fmutex);
199
200         /* stop all device */
201         err = devices_stop();
202         if (err == -ENOTSUP)
203                 return FEEDBACK_ERROR_NOT_SUPPORTED;
204         else if (err == -ECOMM)
205                 return FEEDBACK_ERROR_PERMISSION_DENIED;
206         else if (err < 0)
207                 return FEEDBACK_ERROR_OPERATION_FAILED;
208
209         return FEEDBACK_ERROR_NONE;
210 }
211
212 API int feedback_is_supported_pattern(feedback_type_e type, feedback_pattern_e pattern, bool *status)
213 {
214         const struct device_ops *dev;
215         bool supported;
216         int err;
217         bool result;
218         int switched;
219
220         /* check initialize */
221         pthread_mutex_lock(&fmutex);
222         if (!init_cnt) {
223                 _E("Not initialized"); //LCOV_EXCL_LINE
224                 pthread_mutex_unlock(&fmutex);
225                 return FEEDBACK_ERROR_NOT_INITIALIZED;
226         }
227         pthread_mutex_unlock(&fmutex);
228
229         if (!status) {
230                 _E("Invalid parameter : status(NULL)");
231                 return FEEDBACK_ERROR_INVALID_PARAMETER;
232         }
233
234         if (type <= FEEDBACK_TYPE_NONE ||
235             type >= profile->max_type) {
236                 _E("Invalid parameter : type(%d)", type);
237                 return FEEDBACK_ERROR_INVALID_PARAMETER;
238         }
239
240         if (pattern <= FEEDBACK_PATTERN_NONE ||
241             pattern >= profile->max_pattern) {
242                 _E("Invalid parameter : pattern(%d)", pattern);
243                 return FEEDBACK_ERROR_INVALID_PARAMETER;
244         }
245
246         /* if you need to switch pattern */
247         if (profile->get_switched_pattern) {
248                 result = profile->get_switched_pattern(pattern, &switched);
249                 if (result) {
250                         _W("pattern is changed : (%s) -> (%s)", //LCOV_EXCL_LINE
251                                         profile->str_pattern[pattern], profile->str_pattern[switched]);
252                         pattern = switched;
253                 }
254         }
255
256         /* play proper device */
257         dev = find_device(type);
258         if (!dev) {
259                 _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
260                 return FEEDBACK_ERROR_NOT_SUPPORTED;
261         }
262
263         err = dev->is_supported(pattern, &supported);
264         if (err == -ENOTSUP)
265                 return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error
266         else if (err == -ECOMM || err == -EACCES)
267                 return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE System Error
268         else if (err < 0) {
269                 _E("fail to invoke is_supported() : pattern(%s)", profile->str_pattern[pattern]); //LCOV_EXCL_LINE
270                 return FEEDBACK_ERROR_OPERATION_FAILED;
271         }
272
273         *status = supported;
274
275         return FEEDBACK_ERROR_NONE;
276 }
277
278 /* Internal APIs */
279 API int feedback_play_type_by_name(char *type, char *pattern)
280 {
281         feedback_type_e etype;
282         feedback_pattern_e epattern;
283         int type_max;
284         int pattern_max;
285
286         if (!type || !pattern) {
287                 _E("Invalid parameter : type(%x), pattern(%x)", type, pattern);
288                 return FEEDBACK_ERROR_INVALID_PARAMETER;
289         }
290
291         type_max = profile->max_type;
292         for (etype = 0; etype < type_max; ++etype) {
293                 if (!strncmp(type, profile->str_type[etype], strlen(type)))
294                         break;
295         }
296
297         if (etype == type_max) {
298                 _E("Invalid parameter : type(%s)", type);
299                 return FEEDBACK_ERROR_INVALID_PARAMETER;
300         }
301
302         pattern_max = profile->max_pattern;
303         for (epattern = 0; epattern < pattern_max; ++epattern) {
304                 if (!strncmp(pattern, profile->str_pattern[epattern], strlen(pattern)))
305                         break;
306         }
307
308         if (epattern == pattern_max) {
309                 _E("Invalid parameter : pattern(%s)", pattern);
310                 return FEEDBACK_ERROR_INVALID_PARAMETER;
311         }
312
313         return feedback_play_type(etype, epattern);
314 }
315
316 API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
317 {
318         const struct device_ops *dev;
319         char buf[PATH_MAX] = {0,};
320         int err;
321
322         if (path == NULL) {
323                 _E("Invalid parameter : path(NULL)");
324                 return FEEDBACK_ERROR_INVALID_PARAMETER;
325         }
326
327         if (type <= FEEDBACK_TYPE_NONE ||
328             type >= profile->max_type) {
329                 _E("Invalid parameter : type(%d)", type);
330                 return FEEDBACK_ERROR_INVALID_PARAMETER;
331         }
332
333         if (type == FEEDBACK_TYPE_VIBRATION)
334                 return FEEDBACK_ERROR_NOT_SUPPORTED;
335
336         if (pattern <= FEEDBACK_PATTERN_NONE ||
337             pattern >= profile->max_pattern) {
338                 _E("Invalid parameter : pattern(%d)", pattern);
339                 return FEEDBACK_ERROR_INVALID_PARAMETER;
340         }
341
342         /* proper device get path */
343         dev = find_device(type);
344         if (dev) {
345                 err = dev->get_path(pattern, buf, sizeof(buf));
346                 if (err < 0)
347                         return FEEDBACK_ERROR_OPERATION_FAILED;
348         }
349
350         *path = strdup(buf);
351         return FEEDBACK_ERROR_NONE;
352 }
353
354 API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
355 {
356         const struct device_ops *dev;
357         int err;
358
359         if (type <= FEEDBACK_TYPE_NONE ||
360             type >= profile->max_type) {
361                 _E("Invalid parameter : type(%d)", type);
362                 return FEEDBACK_ERROR_INVALID_PARAMETER;
363         }
364
365         if (pattern <= FEEDBACK_PATTERN_NONE ||
366             pattern >= profile->max_pattern) {
367                 _E("Invalid parameter : pattern(%d)", pattern);
368                 return FEEDBACK_ERROR_INVALID_PARAMETER;
369         }
370
371         if (type == FEEDBACK_TYPE_VIBRATION) {
372                 _E("Not supported type"); //LCOV_EXCL_LINE
373                 return FEEDBACK_ERROR_NOT_SUPPORTED;
374         }
375
376         /* proper device set path */
377         dev = find_device(type);
378         if (dev) {
379                 err = dev->set_path(pattern, path);
380                 if (err < 0)
381                         return FEEDBACK_ERROR_OPERATION_FAILED;
382         }
383
384         return FEEDBACK_ERROR_NONE;
385 }