standard : fix svace issue
[platform/core/system/feedbackd.git] / src / haptic / standard.c
1 /*
2  * feedbackd
3  *
4  * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30 #include <linux/input.h>
31
32 #include "core/log.h"
33 #include "core/list.h"
34 #include "haptic.h"
35
36 #define MAX_MAGNITUDE                   0xFFFF
37 #define PERIODIC_MAX_MAGNITUDE  0x7FFF  /* 0.5 * MAX_MAGNITUDE */
38 #define RUMBLE_MAX_MAGNITUDE    0xFFFF
39
40 #define DEV_INPUT   "/dev/input"
41 #define EVENT           "event"
42
43 #define MAX_DATA 16
44 #define FF_INFO_MAGIC 0xDEADFEED
45
46 struct ff_info_header {
47         unsigned int magic;
48         int iteration;
49         int ff_info_data_count;
50 };
51
52 struct ff_info_data {
53         int type;/* play, stop etc */
54         int magnitude; /* strength */
55         int length; /* in ms for stop, play*/
56 };
57
58 struct ff_info_buffer {
59         struct ff_info_header header;
60         struct ff_info_data data[MAX_DATA];
61 };
62
63 struct ff_info {
64         int handle;
65         guint timer;
66         struct ff_effect effect;
67         struct ff_info_buffer *ffinfobuffer;
68         int currentindex;
69 };
70
71 static int ff_fd;
72 static dd_list *ff_list;
73 static dd_list *handle_list;
74 static char ff_path[PATH_MAX];
75 static int unique_number;
76 static int current_effect_id = -1;
77
78 static int stop_device(int device_handle);
79
80 struct ff_info *read_from_list(int handle)
81 {
82         struct ff_info *temp;
83         dd_list *elem;
84
85         DD_LIST_FOREACH(ff_list, elem, temp) {
86                 if (temp->handle == handle)
87                         return temp;
88         }
89         return NULL;
90 }
91
92 static bool check_valid_handle(struct ff_info *info)
93 {
94         struct ff_info *temp;
95         dd_list *elem;
96
97         DD_LIST_FOREACH(ff_list, elem, temp) {
98                 if (temp == info)
99                         break;
100         }
101
102         if (!temp)
103                 return false;
104         return true;
105 }
106
107 static bool check_fd(int *fd)
108 {
109         int ffd;
110
111         if (*fd > 0)
112                 return true;
113
114         ffd = open(ff_path, O_RDWR);
115         if (ffd < 0)
116                 return false;
117
118         *fd = ffd;
119         return true;
120 }
121
122 static int ff_stop(int fd, struct ff_effect *effect);
123 static gboolean timer_cb(void *data)
124 {
125         struct ff_info *info = (struct ff_info *)data;
126
127         if (!info) {
128                 _E("Failed to check info.");
129                 return G_SOURCE_REMOVE;
130         }
131
132         if (!check_valid_handle(info)) {
133                 _E("Failed to check valied info.");
134                 return G_SOURCE_REMOVE;
135         }
136
137         _I("Stop vibration by timer. id(%d)", info->effect.id);
138
139         /* stop previous vibration */
140         ff_stop(ff_fd, &info->effect);
141
142         /* reset timer */
143         info->timer = 0;
144
145         return G_SOURCE_REMOVE;
146 }
147
148 static int ff_find_device(void)
149 {
150         DIR *dir;
151         struct dirent *dent;
152         char ev_path[PATH_MAX];
153         unsigned long features[1+FF_MAX/sizeof(unsigned long)];
154         int fd, ret;
155
156         dir = opendir(DEV_INPUT);
157         if (!dir)
158                 return -errno;
159
160         while (1) {
161                 dent = readdir(dir);
162                 if (dent == NULL)
163                         break;
164
165                 if (dent->d_type == DT_DIR ||
166                         !strstr(dent->d_name, "event"))
167                         continue;
168
169                 snprintf(ev_path, sizeof(ev_path), "%s/%s", DEV_INPUT, dent->d_name);
170
171                 fd = open(ev_path, O_RDWR);
172                 if (fd < 0) {
173                         _E("Failed to open '%s'.: %d", ev_path, errno);
174                         continue;
175                 }
176
177                 /* get force feedback device */
178                 memset(features, 0, sizeof(features));
179                 ret = ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features);
180                 if (ret == -1) {
181                         close(fd);
182                         continue;
183                 }
184
185                 if (test_bit(FF_CONSTANT, features))
186                         _D("'%s' type: constant", ev_path);
187                 if (test_bit(FF_PERIODIC, features))
188                         _D("'%s' type: periodic", ev_path);
189                 if (test_bit(FF_SPRING, features))
190                         _D("'%s' type: spring", ev_path);
191                 if (test_bit(FF_FRICTION, features))
192                         _D("'%s' type: friction", ev_path);
193                 if (test_bit(FF_RUMBLE, features))
194                         _D("'%s' type: rumble", ev_path);
195
196                 if (test_bit(FF_RUMBLE, features)) {
197                         memcpy(ff_path, ev_path, strlen(ev_path));
198                         ff_path[strlen(ev_path)] = '\0';
199                         close(fd);
200                         closedir(dir);
201                         return 0;
202                 }
203
204                 close(fd);
205         }
206
207         closedir(dir);
208         return -1;
209 }
210
211 static int ff_init_effect(struct ff_effect *effect)
212 {
213         if (!effect)
214                 return -EINVAL;
215
216         /*Only rumble supported as of now*/
217         effect->type = FF_RUMBLE;
218         effect->replay.length = 0;
219         effect->replay.delay = 10;
220         effect->id = -1;
221         effect->u.rumble.strong_magnitude = 0;
222
223         return 0;
224 }
225
226 static int ff_set_effect(struct ff_effect *effect, int length, int level)
227 {
228         double magnitude;
229
230         if (!effect) {
231                 _E("There is no valid effect.");
232                 return -EINVAL;
233         }
234
235         magnitude = (double)level/HAPTIC_MODULE_FEEDBACK_MAX;
236         magnitude *= RUMBLE_MAX_MAGNITUDE;
237
238         _I("magnitude=%d length=%d", (int)magnitude, length);
239
240         /* set member variables in effect struct */
241         effect->u.rumble.strong_magnitude = (int)magnitude;
242         effect->replay.length = length;         /* length millisecond */
243
244         return 0;
245 }
246
247 static int ff_play(int fd, struct ff_effect *effect)
248 {
249         struct input_event play;
250         int ret;
251
252         if (fd < 0 || !effect) {
253                 _E("Fd(%d) or effect(%s) is invalid", fd, effect ? "not null" : "null");
254                 return -EINVAL;
255         }
256
257         /* upload an effect */
258         if (current_effect_id == -1) {
259                 if (ioctl(fd, EVIOCSFF, effect) == -1) {
260                         _E("Failed to ioctl");
261                         return -errno;
262                 }
263                 current_effect_id = effect->id;
264         } else
265                 effect->id = current_effect_id;
266
267         /* play vibration*/
268         play.type = EV_FF;
269         play.code = effect->id;
270         play.value = 1; /* 1 : PLAY, 0 : STOP */
271
272         ret = write(fd, (const void *)&play, sizeof(play));
273         if (ret == -1) {
274                 _E("Failed to write");
275                 return -errno;
276         }
277
278         return 0;
279 }
280
281 static int ff_stop(int fd, struct ff_effect *effect)
282 {
283         struct input_event stop;
284         int ret;
285
286         if (fd < 0 || !effect)
287                 return -EINVAL;
288
289         if (effect->id == -1) {
290                 if (current_effect_id == -1)
291                         return 0;
292                 effect->id = current_effect_id;
293         }
294
295         /* Stop vibration */
296         stop.type = EV_FF;
297         stop.code = effect->id;
298         stop.value = 0; /* 1 : PLAY, 0 : STOP */
299         ret = write(fd, (const void *)&stop, sizeof(stop));
300         if (ret == -1)
301                 return -errno;
302
303         /* removing an effect from the device */
304         if (ioctl(fd, EVIOCRMFF, effect->id) == -1)
305                 return -errno;
306
307         /* reset effect id */
308         effect->id = -1;
309         current_effect_id = -1;
310
311         return 0;
312 }
313
314 /* START: Haptic Module APIs */
315 static int get_device_count(int *count)
316 {
317         /* suppose there is just one haptic device */
318         if (count)
319                 *count = 1;
320
321         return 0;
322 }
323
324 static int open_device(int device_index, int *device_handle)
325 {
326         struct ff_info *info;
327         int n;
328         bool found = false;
329         dd_list *elem;
330
331         if (!device_handle)
332                 return -EINVAL;
333
334         /* if it is the first element */
335         n = DD_LIST_LENGTH(ff_list);
336         if (n == 0 && !ff_fd) {
337                 _I("First element: open ff driver");
338                 /* open ff driver */
339                 ff_fd = open(ff_path, O_RDWR);
340                 if (ff_fd < 0) {
341                         _E("Failed to open %s : %d", ff_path, errno);
342                         return -errno;
343                 }
344         }
345
346         /* allocate memory */
347         info = calloc(sizeof(struct ff_info), 1);
348         if (!info) {
349                 _E("Failed to allocate memory : %d", errno);
350                 return -errno;
351         }
352
353         /* initialize ff_effect structure */
354         ff_init_effect(&info->effect);
355
356         if (unique_number == INT_MAX)
357                 unique_number = 0;
358
359         while (found != true) {
360                 ++unique_number;
361                 elem = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
362                 if (!elem)
363                         found = true;
364         }
365
366         info->handle = unique_number;
367
368         /* add info to local list */
369         DD_LIST_APPEND(ff_list, info);
370         DD_LIST_APPEND(handle_list, (gpointer)(long)info->handle);
371
372         *device_handle = info->handle;
373         return 0;
374 }
375
376 static int close_device(int device_handle)
377 {
378         struct ff_info *info;
379         int n;
380
381         info = read_from_list(device_handle);
382         if (!info) {
383                 _E("Handle %d failed to check info", device_handle);
384                 return -ENOENT; /* 2 */
385         }
386
387         if (!check_valid_handle(info)) {
388                 _E("Handle %d failed to check valid handle", device_handle);
389                 return -EINVAL; /* 22 */
390         }
391
392         if (!check_fd(&ff_fd)) {
393                 _E("Handle %d failed to check fd", device_handle);
394                 return -ENODEV; /* 19 */
395         }
396
397         /* stop vibration */
398         stop_device(device_handle);
399
400         DD_LIST_REMOVE(handle_list, (gpointer)(long)info->handle);
401
402         safe_free(info->ffinfobuffer);
403         /* remove info from local list */
404         DD_LIST_REMOVE(ff_list, info);
405         safe_free(info);
406
407         /* if it is the last element */
408         n = DD_LIST_LENGTH(ff_list);
409         if (n == 0 && ff_fd) {
410                 _I("Last element: close ff driver");
411                 /* close ff driver */
412                 close(ff_fd);
413                 ff_fd = 0;
414         }
415
416         return 0;
417 }
418
419 static int vibrate_monotone(int device_handle, int duration, int feedback, int priority)
420 {
421         struct ff_info *info;
422         int ret;
423
424         info = read_from_list(device_handle);
425         if (!info) {
426                 _E("Handle %d failed to check list", device_handle);
427                 return -EINVAL;
428         }
429
430         if (!check_valid_handle(info)) {
431                 _E("Handle %d failed to check handle", device_handle);
432                 return -EINVAL;
433         }
434
435         if (!check_fd(&ff_fd))
436                 return -ENODEV;
437
438         if (duration <= 0) {
439                 _I("Handle %d skip requests with duration 0", device_handle);
440                 return 0;
441         }
442
443         /* Zero(0) is the infinitely vibration value */
444         if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
445                 duration = 0;
446
447         /* unregister existing timer */
448         if (info->timer) {
449                 ff_stop(ff_fd, &info->effect);
450                 g_source_remove(info->timer);
451                 info->timer = 0;
452         }
453
454         /* set effect as per arguments */
455         ff_init_effect(&info->effect);
456         ret = ff_set_effect(&info->effect, duration, feedback);
457         if (ret < 0) {
458                 _E("Handle %d fail to set effect(duration:%d, feedback:%d) : %d",
459                                 device_handle, duration, feedback, ret);
460                 return ret;
461         }
462
463         /* play effect as per arguments */
464         ret = ff_play(ff_fd, &info->effect);
465         if (ret < 0) {
466                 _E("Handle %d fail to play haptic effect(fd:%d id:%d) : %d",
467                                 device_handle, ff_fd, info->effect.id, ret);
468                 return ret;
469         }
470
471         /* register timer */
472         if (duration) {
473                 info->timer = g_timeout_add(duration, timer_cb, info);
474                 if (!info->timer)
475                         _E("Handle %d failed to add timer callback", device_handle);
476         }
477
478         _D("Handle %d effect id : %d %dms", device_handle, info->effect.id, duration);
479
480         return 0;
481 }
482
483 static int stop_device(int device_handle)
484 {
485         struct ff_info *info;
486         int r;
487
488         info = read_from_list(device_handle);
489         if (!info) {
490                 _E("Handle %d fail to check info", device_handle);
491                 return -ENOENT; /* 2 */
492         }
493
494         if (!check_valid_handle(info)) {
495                 _E("Handle %d fail to check handle", device_handle);
496                 return -EINVAL; /* 22 */
497         }
498
499         if (!check_fd(&ff_fd)) {
500                 _E("Handle %d fail to check fd", device_handle);
501                 return -ENODEV; /* 19 */
502         }
503
504         if (cur_h_data.handle > 0 && cur_h_data.handle != info->handle) {
505                 _E("Only same handle can stop current vibration");
506                 return -EPERM;
507         }
508
509         /* stop effect */
510         r = ff_stop(ff_fd, &info->effect);
511         if (r < 0)
512                 _E("failed to stop effect(id:%d) : %d", info->effect.id, r);
513         else
514                 _D("succeed to stop effect");
515
516         /* unregister existing timer */
517         if (r >= 0 && info->timer) {
518                 g_source_remove(info->timer);
519                 info->timer = 0;
520         }
521
522         return 0;
523 }
524 /* END: Haptic Module APIs */
525
526 static const struct haptic_plugin_ops default_plugin = {
527         .get_device_count    = get_device_count,
528         .open_device         = open_device,
529         .close_device        = close_device,
530         .vibrate_monotone    = vibrate_monotone,
531         .stop_device         = stop_device,
532 };
533
534 static bool is_valid(void)
535 {
536         int ret;
537
538         ret = ff_find_device();
539         if (ret < 0) {
540                 _E("Do not support standard haptic device");
541                 return false;
542         }
543
544         _I("Support standard haptic device");
545         return true;
546 }
547
548 static const struct haptic_plugin_ops *load(void)
549 {
550         return &default_plugin;
551 }
552
553 static const struct haptic_ops std_ops = {
554         .type     = HAPTIC_STANDARD,
555         .is_valid = is_valid,
556         .load     = load,
557 };
558
559 HAPTIC_OPS_REGISTER(&std_ops)