Modify feedback operation
[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 //LCOV_EXCL_START Internal APIs. TODO Will make iUTC
279 /* Internal APIs */
280 API int feedback_play_type_by_name(char *type, char *pattern)
281 {
282         feedback_type_e etype;
283         feedback_pattern_e epattern;
284         int type_max;
285         int pattern_max;
286
287         if (!type || !pattern) {
288                 _E("Invalid parameter : type(%x), pattern(%x)", type, pattern);
289                 return FEEDBACK_ERROR_INVALID_PARAMETER;
290         }
291
292         type_max = profile->max_type;
293         for (etype = 0; etype < type_max; ++etype) {
294                 if (!strncmp(type, profile->str_type[etype], strlen(type)))
295                         break;
296         }
297
298         if (etype == type_max) {
299                 _E("Invalid parameter : type(%s)", type);
300                 return FEEDBACK_ERROR_INVALID_PARAMETER;
301         }
302
303         pattern_max = profile->max_pattern;
304         for (epattern = 0; epattern < pattern_max; ++epattern) {
305                 if (!strncmp(pattern, profile->str_pattern[epattern], strlen(pattern)))
306                         break;
307         }
308
309         if (epattern == pattern_max) {
310                 _E("Invalid parameter : pattern(%s)", pattern);
311                 return FEEDBACK_ERROR_INVALID_PARAMETER;
312         }
313
314         return feedback_play_type(etype, epattern);
315 }
316
317 API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
318 {
319         const struct device_ops *dev;
320         char buf[PATH_MAX] = {0,};
321         int err;
322
323         if (path == NULL) {
324                 _E("Invalid parameter : path(NULL)");
325                 return FEEDBACK_ERROR_INVALID_PARAMETER;
326         }
327
328         if (type <= FEEDBACK_TYPE_NONE ||
329             type >= profile->max_type) {
330                 _E("Invalid parameter : type(%d)", type);
331                 return FEEDBACK_ERROR_INVALID_PARAMETER;
332         }
333
334         if (type == FEEDBACK_TYPE_VIBRATION)
335                 return FEEDBACK_ERROR_NOT_SUPPORTED;
336
337         if (pattern <= FEEDBACK_PATTERN_NONE ||
338             pattern >= profile->max_pattern) {
339                 _E("Invalid parameter : pattern(%d)", pattern);
340                 return FEEDBACK_ERROR_INVALID_PARAMETER;
341         }
342
343         /* proper device get path */
344         dev = find_device(type);
345         if (dev) {
346                 err = dev->get_path(pattern, buf, sizeof(buf));
347                 if (err < 0)
348                         return FEEDBACK_ERROR_OPERATION_FAILED;
349         }
350
351         *path = strdup(buf);
352         return FEEDBACK_ERROR_NONE;
353 }
354
355 API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
356 {
357         const struct device_ops *dev;
358         int err;
359
360         if (type <= FEEDBACK_TYPE_NONE ||
361             type >= profile->max_type) {
362                 _E("Invalid parameter : type(%d)", type);
363                 return FEEDBACK_ERROR_INVALID_PARAMETER;
364         }
365
366         if (pattern <= FEEDBACK_PATTERN_NONE ||
367             pattern >= profile->max_pattern) {
368                 _E("Invalid parameter : pattern(%d)", pattern);
369                 return FEEDBACK_ERROR_INVALID_PARAMETER;
370         }
371
372         if (type == FEEDBACK_TYPE_VIBRATION) {
373                 _E("Not supported type");
374                 return FEEDBACK_ERROR_NOT_SUPPORTED;
375         }
376
377         /* proper device set path */
378         dev = find_device(type);
379         if (dev) {
380                 err = dev->set_path(pattern, path);
381                 if (err < 0)
382                         return FEEDBACK_ERROR_OPERATION_FAILED;
383         }
384
385         return FEEDBACK_ERROR_NONE;
386 }
387 //LCOV_EXCL_STOP