tizen 2.4 release
[adaptation/xorg/driver/xserver-xorg-input-evdev.git] / src / rotary.c
1 /*
2  *
3  * xserver-xorg-input-evdev
4  *
5  * Contact: Sung-Jin Park <sj76.park@samsung.com>
6  *          Sangjin LEE <lsj119@samsung.com>
7  *          Jeonghyun Kang <jhyuni.kang@samsung.com>
8  *          Hyung-Joon Jeon <helius.jeon@samsung.com>
9  *          Minsu Han <minsu81.han@samsung.com>
10  *          YoungHoon Song <ysens.song@samsung.com>
11  *
12  * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
13  * Copyright © 2004-2008 Red Hat, Inc.
14  *
15  * Permission to use, copy, modify, distribute, and sell this software
16  * and its documentation for any purpose is hereby granted without
17  * fee, provided that the above copyright notice appear in all copies
18  * and that both that copyright notice and this permission notice
19  * appear in supporting documentation, and that the name of Red Hat
20  * not be used in advertising or publicity pertaining to distribution
21  * of the software without specific, written prior permission.  Red
22  * Hat makes no representations about the suitability of this software
23  * for any purpose.  It is provided "as is" without express or implied
24  * warranty.
25  *
26  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
27  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
28  * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
29  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
30  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
31  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
32  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33  *
34  * Authors:
35  *      Kristian Høgsberg (krh@redhat.com)
36  *      Adam Jackson (ajax@redhat.com)
37  *      Peter Hutterer (peter.hutterer@redhat.com)
38  *      Oliver McFadden (oliver.mcfadden@nokia.com)
39  */
40
41 #ifdef _F_EVDEV_SUPPORT_ROTARY_
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include <evdev.h>
48 #include <evdev-properties.h>
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54
55 #include <exevents.h>
56 #include <xf86.h>
57 #include <xf86Xinput.h>
58
59 #define IDLE 0
60 #define MOVING 1
61
62 #define SW_ROTARY_MAX 3600 // Mathematical rotary angular position limit (i.e. 360) scaled by CALCULATOR_VALUE.
63
64 #define DETENT_TOLERANCE 20
65 #define DETENT_TIMEOUT_TOLERANCE 30
66
67 #define DETENT_TIMEOUT 500
68 #define START_TIMEOUT 2000
69 #define RETURN_TIMEOUT 200
70
71 #define NO_VALUE 0
72 #define CALCULATOR_VALUE 10     //for 3600-base angle
73 #define DETENT_INTERVAL 150
74
75 #define NULL_DETENT 255 // driver-side constant for null-detent event
76 #define RIGHT_DETENT 1 // driver-side constant for detent event moving right(clockwise)
77 #define LEFT_DETENT -1 // driver-side constant for detent event moving left(counter-clockwise)
78 #define ZERO_DETENT 0 // driver-side constant for detent event moving away from and then towards detent position
79
80 #define HALL_LEFT 1
81 #define HALL_CENTER 2
82 #define HALL_RIGHT 3
83
84 #define HALLIC_DETENT_RIGHT 2 // kernel-side constant for detent event moving right(clockwise)
85 #define HALLIC_DETENT_LEFT -2 // kernel-side constant for detent event moving left(counter-clockwise)
86 #define HALLIC_MOVE_OUT 1 // kernel-side constant for move event away from detent position
87 #define HALLIC_MOVE_IN -1 // kernel-side constant for move event towards detent position
88
89 #define NO_DEVICE 0
90 #define OFM_DEVICE 1
91 #define HALL_DEVICE 2
92
93 #define ENABLE_TIMER 0
94 #define DELETE_TIMER 1
95
96 //#define __DETAIL_DEBUG__
97
98 #ifdef __DETAIL_DEBUG__
99 #define DetailDebugPrint LogMessageVerbSigSafe
100 #else
101 #define DetailDebugPrint(...)
102 #endif
103
104 static int hasRotary = NO_DEVICE;
105 static int hasDetent = NO_DEVICE;
106
107 static int hw_rotary_max; // HW rotary angular position limit scaled by CALCULATOR_VALUE.
108 static double kernel_angle_step;
109 static int return_tolerance;
110
111 static OsTimerPtr detent_event_timer = NULL;
112 static OsTimerPtr start_event_timer = NULL;
113 static int start_event_timer_flag = ENABLE_TIMER;
114
115
116 static int angle_pos_raw = 0; //angular position within kernel-side range of about 0~hw_rotary_max. It resets to 0 upon timer event.
117 static int angle_pos = 0; // angular position within driver-side full range of 0~SW_ROTARY_MAX. It does not reset to 0 upon timer event.
118 static int angle_pos_sub_cal = 0; // angular position within driver-side sub-range of -ROTATE_DETENT_INTERVAL~ROTATE_DETENT_INTERVAL. It resets to 0 upon timer event.
119 static unsigned char is_detent = 0;
120 static int detent_sum = 0;
121 static int state = IDLE;
122 static int temp_sub_cal = 0;
123 static int event_time = 0;
124 static int angle_delta_dir=0; // rotation direction
125 static int return_state = 0;
126
127 static int ignore_state = 0;
128 static int ignore_angle = 0;
129 static int return_ignore_state = 0;
130 static int return_ignore_angle = 0;
131 static int return_ignore_reset_condition = 0;
132
133 static int detent_hall_ic = 0;
134 static int detent_hall_ic_prev = 0;
135 static int hall_ic_count = -1;
136
137 static int setRotaryFlag = 0;
138 static int setDetentFlag = 0;
139
140 #ifdef _F_GESTURE_EXTENSION_
141
142 #define ROTARY_FRAME_SYNC_TIMEOUT 200
143 #define ROTARY_FRAME_SYNC_TOLERANCE 30
144
145 static OsTimerPtr rotary_frame_sync_timer = NULL;
146 static unsigned char is_touch_blocked = 0;
147
148 extern void mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e);
149 void EvdevRotarySync(InputInfoPtr pInfo, MTSyncType sync)
150 {
151     AnyEvent event;
152
153     memset(&event, 0, sizeof(event));
154     event.header = ET_Internal;
155     event.type = ET_MTSync;
156     event.length = sizeof(event);
157     event.time = GetTimeInMillis();
158     event.deviceid = pInfo->dev->id;
159     event.sync = sync;
160     mieqEnqueue (pInfo->dev, (InternalEvent*)&event);
161 }
162 static CARD32 EvdevRotarySyncTimerFinish(OsTimerPtr timer, CARD32 time, pointer arg)
163 {
164     InputInfoPtr pInfo = (InputInfoPtr)arg;
165
166     if (is_touch_blocked == 0)
167     {
168         TimerCancel(rotary_frame_sync_timer);
169         return 0;
170     }
171
172     DetailDebugPrint(X_INFO, 1, "[EvdevRotarySyncTimerFinish] Touch is freed from blocking.\n");
173     EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_END);
174     is_touch_blocked = 0;
175
176     return 0;
177 }
178 #endif
179
180 static CARD32
181 ResetValues(OsTimerPtr timer, CARD32 time, pointer arg)
182 {
183     angle_pos_sub_cal = 0;
184     angle_pos_raw = 0;
185     detent_sum = 0;
186     temp_sub_cal = 0;
187     ignore_state = 0;
188     ignore_angle = 0;
189     angle_delta_dir = 0;
190     return_ignore_state = 0;
191     return_ignore_angle = 0;
192     detent_hall_ic = 0;
193     return_ignore_reset_condition = 0;
194     hall_ic_count = -1;
195     setRotaryFlag = 0;
196     setDetentFlag = 0;
197
198     state = IDLE;
199     DetailDebugPrint(X_INFO, 1, "[ResetValues] Reset all values!\n");
200
201     return 0;
202 }
203
204 static void
205 DeliverDetentEvent(InputInfoPtr pInfo, int type, int value)
206 {
207     EvdevPtr pEvdev = pInfo->private;
208     int detent_type;
209
210     event_time = GetTimeInMillis();
211
212     valuator_mask_set(pEvdev->vals, REL_X, value);
213     valuator_mask_set(pEvdev->vals, REL_Y, event_time);
214
215     if (type == 0)
216         detent_type = 0;
217     else
218         detent_type = 1;
219
220     valuator_mask_set(pEvdev->vals, REL_Z, detent_type);
221     xf86PostMotionEventM(pInfo->dev, Relative, pEvdev->vals);
222
223     detent_sum++;
224     DetailDebugPrint(X_INFO, 1, "[Deliver PreDetent] X=%d, angle_pos_sub_cal=%d, detent=%d, time=%d\n", value, angle_pos_sub_cal, detent_type, event_time);
225 }
226
227 static CARD32
228 RotaryReset(OsTimerPtr timer, CARD32 time, pointer arg)
229 {
230     InputInfoPtr pInfo = (InputInfoPtr)arg;
231
232     EvdevPtr pEvdev = pInfo->private;
233
234     if (start_event_timer_flag && (timer == start_event_timer))
235     {
236         start_event_timer_flag = ENABLE_TIMER;
237         TimerCancel(start_event_timer);
238         return 0;
239     }
240
241     if ((detent_sum != 0) && (return_ignore_reset_condition == 0) &&
242             ((angle_pos_sub_cal <= DETENT_TIMEOUT_TOLERANCE && angle_pos_sub_cal >= -DETENT_TIMEOUT_TOLERANCE)))
243     {
244         DetailDebugPrint(X_INFO, 1, "[RotaryReset] angle_pos_sub_cal=%d, detent_sum=%d, time=%d. All values set to 0.\n", angle_pos_sub_cal, detent_sum, event_time);
245
246         ResetValues(NULL, 1, NULL);
247     }
248     else
249     {
250         DetailDebugPrint(X_INFO, 1, "[No Reset] angle_pos_sub_cal=%d.\n", angle_pos_sub_cal);
251         temp_sub_cal = angle_pos_sub_cal;
252
253         if (return_ignore_state == 1)
254         {
255             ResetValues(NULL, 1, NULL);
256             DetailDebugPrint(X_INFO, 1, "[Reset return ignore state] return_ignore_state=%d.\n", return_ignore_state);
257             return;
258         }
259
260         {
261             DetailDebugPrint(X_INFO, 1, "[Reset] Stop between detents !\n");
262
263             if (detent_hall_ic > 0)
264             {
265                 DetailDebugPrint(X_INFO, 1, "[Reset] Find hall ic event!Deliver detent event\n");
266                 ResetValues(NULL, 1, NULL);
267                 return;
268             }
269         }
270     }
271
272     if (detent_event_timer)
273     {
274         TimerCancel(detent_event_timer);
275     }
276
277     return 0;
278 }
279
280 static void EvdevRotaryProcessHallIcEvent(InputInfoPtr pInfo, int num_v, int first_v,
281         int v[MAX_VALUATORS])
282 {
283     EvdevPtr pEvdev = pInfo->private;
284     int detent_count = 0;
285     int move_count = 0;
286
287     event_time = GetTimeInMillis();
288
289     detent_hall_ic = valuator_mask_get(pEvdev->vals, REL_Z);
290     switch(detent_hall_ic)
291     {
292         case HALLIC_DETENT_RIGHT:
293             detent_count = RIGHT_DETENT;
294             break;
295         case HALLIC_DETENT_LEFT:
296             detent_count = LEFT_DETENT;
297             break;
298         case HALLIC_MOVE_OUT:
299             detent_count = ZERO_DETENT;
300             move_count = 1;
301             break;
302         case HALLIC_MOVE_IN:
303             detent_count = ZERO_DETENT;
304             break;
305         default:
306             LogMessageVerbSigSafe(X_WARNING, 1, "[EvdevRotaryProcessHallIcEvent] Unknown Hall IC event! assuming HALLIC_MOVE_IN.\n");
307             detent_count = ZERO_DETENT;
308             break;
309     }
310     DetailDebugPrint(X_INFO, 1, "[HALL Only] REL_Z=%d, detent_count=%d, time=%d\n", detent_hall_ic, detent_count, event_time);
311
312 #ifdef _F_GESTURE_EXTENSION_
313     if(move_count)
314     {
315         DetailDebugPrint(X_INFO, 1, "[EvdevRotaryProcessHallIcEvent] Rotary is moving...touch is blocked!\n");
316         if(is_touch_blocked == 0)
317         {
318             EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
319             is_touch_blocked = 1;
320         }
321         rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
322         return;
323     }
324 #endif
325
326     if(!(DPMSPowerLevel == DPMSModeOff || DPMSPowerLevel == DPMSModeSuspend))
327     {
328 #ifdef _F_GESTURE_EXTENSION_
329         if(is_touch_blocked == 1)
330         {
331             EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_END);
332             is_touch_blocked = 0;
333         }
334 #endif
335
336         valuator_mask_set(pEvdev->vals, REL_X, NO_VALUE);
337         valuator_mask_set(pEvdev->vals, REL_Y, event_time);
338         valuator_mask_set(pEvdev->vals, REL_Z, detent_count);
339         xf86PostMotionEventM(pInfo->dev, Relative, pEvdev->vals);
340         LogMessageVerbSigSafe(X_INFO, 1, "[Detent] Hall ic detent has been sent. raw_data=%d, time=%d, detent=%d \n", detent_hall_ic, event_time, detent_count);
341     }
342     else
343         DetailDebugPrint(X_INFO, 1, "[No detent] DPMS off or suspend.\n");
344
345     detent_hall_ic = 0;
346
347 }
348
349 static void EvdevRotaryProcessLegacyHallIcEvent(InputInfoPtr pInfo, int num_v, int first_v,
350         int v[MAX_VALUATORS])
351 {
352     EvdevPtr pEvdev = pInfo->private;
353     int detent_count = 0;
354
355     event_time = GetTimeInMillis();
356
357     detent_hall_ic = valuator_mask_get(pEvdev->vals, REL_Z);
358
359     valuator_mask_set(pEvdev->vals, REL_X, NO_VALUE);
360     valuator_mask_set(pEvdev->vals, REL_Y, event_time);
361
362     if (!detent_hall_ic_prev)
363     {
364         if (angle_pos_raw > 0)
365         {
366             detent_count = RIGHT_DETENT;
367             LogMessageVerbSigSafe(X_INFO, 1, "[OFM+HALL] REL_Z=%d, angle_pos_raw=%d, detent_count=%d, time=%d\n", detent_hall_ic, angle_pos_raw, detent_count, event_time);
368         }
369         else if (angle_pos_raw < 0)
370         {
371             detent_count = LEFT_DETENT;
372             LogMessageVerbSigSafe(X_INFO, 1, "[OFM+HALL] REL_Z=%d, angle_pos_raw=%d, detent_count=%d, time=%d\n", detent_hall_ic, angle_pos_raw, detent_count, event_time);
373         }
374     }
375
376     // Only hall ic
377     else
378     {
379         switch(detent_hall_ic)
380         {
381             case HALL_LEFT :
382                 if (detent_hall_ic_prev == HALL_CENTER)
383                     detent_count = LEFT_DETENT;
384                 else if (detent_hall_ic_prev == HALL_RIGHT)
385                     detent_count = RIGHT_DETENT;
386                 break;
387             case HALL_CENTER :
388                 if (detent_hall_ic_prev == HALL_RIGHT)
389                         detent_count = LEFT_DETENT;
390                 else if (detent_hall_ic_prev == HALL_LEFT)
391                         detent_count = RIGHT_DETENT;
392                 break;
393             case HALL_RIGHT :
394                 if (detent_hall_ic_prev == HALL_LEFT)
395                         detent_count = LEFT_DETENT;
396                 else if (detent_hall_ic_prev == HALL_CENTER)
397                         detent_count = RIGHT_DETENT;
398                 break;
399             default :
400                 break;
401         }
402
403         DetailDebugPrint(X_INFO, 1, "[HALL Only] REL_Z_Prev=%d, REL_Z=%d, detent_count=%d, time=%d\n", detent_hall_ic_prev, detent_hall_ic, detent_count, event_time);
404     }
405
406     valuator_mask_set(pEvdev->vals, REL_Z, detent_count);
407
408     if((!(DPMSPowerLevel == DPMSModeOff || DPMSPowerLevel == DPMSModeSuspend)) && (setRotaryFlag == 0))
409     {
410         xf86PostMotionEventM(pInfo->dev, Relative, pEvdev->vals);
411 #ifdef _F_GESTURE_EXTENSION_
412         if(is_touch_blocked == 0)
413         {
414             EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
415             is_touch_blocked = 1;
416         }
417         rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
418 #endif
419         setDetentFlag = 1;
420         LogMessageVerbSigSafe(X_INFO, 1, "[Rotary] Hall ic detent has been sent. setRotaryFlag=%d, setDetentFlag=%d, raw_data=%d, time=%d, detent=%d \n", setRotaryFlag, setDetentFlag, detent_hall_ic, event_time, detent_count);
421     }
422     else
423         DetailDebugPrint(X_INFO, 1, "[Rotary] DPMS off or suspend or rotary detent has already been sent. setRotaryFlag=%d, setDetentFlag=%d \n", setRotaryFlag, setDetentFlag);
424
425     detent_hall_ic_prev = detent_hall_ic;
426     detent_hall_ic = 0;
427     angle_pos_raw = 0;
428
429     return;
430 }
431
432 static void EvdevRotaryProcessOfmEvent(InputInfoPtr pInfo, int num_v, int first_v,
433         int v[MAX_VALUATORS])
434 {
435     int angle_delta_raw=0; // kernel-side rotation angle scaled by CALCULATOR_VALUE
436     int angle_delta_cal=0; // actual rotation angle scaled by CALCULATOR_VALUE, in integer format
437
438     int detent_count=0;
439     int i;
440
441     EvdevPtr pEvdev = pInfo->private;
442
443     DeviceIntPtr dev;
444     InputInfoPtr pInfoDetent;
445     EvdevPtr pEvdevDetent;
446
447     event_time = GetTimeInMillis();
448
449     angle_delta_raw = valuator_mask_get(pEvdev->vals, REL_X) * CALCULATOR_VALUE;
450     angle_delta_cal = (int)((angle_pos_raw + angle_delta_raw) * (double)kernel_angle_step) - (int)(angle_pos_raw * (double)kernel_angle_step);
451
452     angle_pos_raw += angle_delta_raw;
453     if (angle_pos_raw >= hw_rotary_max || angle_pos_raw <= -hw_rotary_max)
454         angle_pos_raw = angle_pos_raw % hw_rotary_max;
455
456     angle_pos_sub_cal += angle_delta_cal;
457
458     angle_pos += angle_delta_cal;
459     if( angle_pos > SW_ROTARY_MAX-1 )
460         angle_pos = angle_pos % SW_ROTARY_MAX;
461     else if( angle_pos < 0 )
462         angle_pos = SW_ROTARY_MAX + angle_pos % SW_ROTARY_MAX;
463
464     if (hall_ic_count >= 0)
465     {
466         hall_ic_count++;
467         if (hall_ic_count > 2)
468         {
469             DetailDebugPrint(X_INFO, 1, "[Detent hall ic count up] hall_ic_count=%d\n", hall_ic_count);
470             start_event_timer = TimerSet(start_event_timer, 0, 1, RotaryReset, pInfo);
471             hall_ic_count = -1;
472             return;
473         }
474     }
475
476     if (ignore_state == 1)
477     {
478         ignore_angle += angle_delta_cal;
479
480         if (ignore_angle * angle_delta_cal < 0)
481         {
482             if ((ignore_angle < DETENT_INTERVAL - DETENT_TOLERANCE) && (ignore_angle > -DETENT_INTERVAL + DETENT_TOLERANCE))
483             {
484                 DetailDebugPrint(X_INFO, 1, "[Opposite direction] ignore_angle=%d, angle_delta_cal=%d, Reset!!\n", ignore_angle, angle_delta_cal);
485                 ignore_state = 0;
486                 ignore_angle = 0;
487
488                 detent_event_timer = TimerSet(detent_event_timer, 0, 1, ResetValues, NULL);
489             }
490             else
491             {
492                 DetailDebugPrint(X_INFO, 1, "[Opposite direction, inside threshold] ignore_angle=%d, angle_delta_cal=%d, No Reset.\n", ignore_angle, angle_delta_cal);
493             }
494             return;
495         }
496         else
497         {
498             if ((ignore_angle >= DETENT_INTERVAL + DETENT_TIMEOUT_TOLERANCE) || (ignore_angle <= -DETENT_INTERVAL - DETENT_TIMEOUT_TOLERANCE))
499             {
500                 DetailDebugPrint(X_INFO, 1, "[No Deliver] ignore_angle=%d, Reset!!\n", ignore_angle);
501                 ignore_state = 0;
502                 ignore_angle = 0;
503
504                 detent_event_timer = TimerSet(detent_event_timer, 0, 1, ResetValues, NULL);
505             }
506
507             else
508                 DetailDebugPrint(X_INFO, 1, "[No Deliver] raw_X=%d, kernel_angle=%d, X=%d, ignore_angle=%d, ignore_state=%d, detent=%d, move_sum=%d\n", angle_delta_raw, angle_pos_raw, angle_delta_cal, ignore_angle, ignore_state, NULL_DETENT, angle_pos_sub_cal);
509             return;
510         }
511     }
512
513     if (return_ignore_state  == 1)
514     {
515         return_ignore_angle += angle_delta_cal;
516
517         if ((return_ignore_angle < DETENT_TIMEOUT_TOLERANCE) && (return_ignore_angle > -DETENT_TIMEOUT_TOLERANCE))
518         {
519             DetailDebugPrint(X_INFO, 1, "[No Deliver] return direction, inside threshold, return_ignore_angle=%d, angle_delta_cal=%d\n", return_ignore_angle, angle_delta_cal);
520             return;
521         }
522         else
523             return_ignore_reset_condition = 1;
524     }
525
526     if( angle_delta_cal == 0 )
527     {
528         DetailDebugPrint(X_INFO, 1, "[No Detent0] raw_X=%d, kernel_angle=%d, X=0, angle=%d\n", angle_delta_raw, angle_pos_raw, angle_pos);
529     }
530     else // angle_delta_cal != 0
531     {
532         // angle_pos_sub_cal 150 ~ -150
533         if( angle_pos_sub_cal >= (DETENT_INTERVAL - DETENT_TIMEOUT_TOLERANCE) ||
534                 angle_pos_sub_cal <= (-DETENT_INTERVAL + DETENT_TIMEOUT_TOLERANCE))
535         {
536             is_detent = 1; // Set detent flag
537
538             if( angle_pos_sub_cal >= DETENT_INTERVAL ) // right direction, NO need to consider tolerance
539             {
540                 detent_count = angle_pos_sub_cal / DETENT_INTERVAL;
541             }
542             else if( angle_pos_sub_cal <= -DETENT_INTERVAL ) // left direction, NO need to consider tolerance
543             {
544                 detent_count = -angle_pos_sub_cal / DETENT_INTERVAL;
545             }
546             else // right or left direction, NEED to consider tolerance!
547             {
548                 detent_count = 1;
549             }
550             detent_sum += detent_count;
551
552         }
553
554         valuator_mask_set(pEvdev->vals, REL_X, angle_delta_cal);
555         valuator_mask_set(pEvdev->vals, REL_Y, event_time);
556
557         if( is_detent == 1 ) // detent
558         {
559             ignore_state = 1;
560             ignore_angle = angle_pos_sub_cal % DETENT_INTERVAL;
561             detent_hall_ic = 0;
562             hall_ic_count = -1;
563
564             if (angle_pos_sub_cal > 0)
565                 detent_count = RIGHT_DETENT;
566             else
567                 detent_count = LEFT_DETENT;
568
569             if (!setDetentFlag)
570             {
571                 for (dev = inputInfo.keyboard; dev; dev = dev->next)
572                 {
573                     if (!strncmp(dev->name, "tizen_detent", strlen(dev->name)))
574                     {
575                         pInfoDetent = dev->public.devicePrivate;
576                         pEvdevDetent = pInfoDetent->private;
577                         break;
578                     }
579                 }
580
581                 valuator_mask_set(pEvdevDetent->vals, REL_X, NO_VALUE);
582                 valuator_mask_set(pEvdevDetent->vals, REL_Y, event_time);
583                 valuator_mask_set(pEvdevDetent->vals, REL_Z, detent_count);
584                 xf86PostMotionEventM(pInfoDetent->dev, Relative, pEvdevDetent->vals);
585 #ifdef _F_GESTURE_EXTENSION_
586                 if(is_touch_blocked == 0)
587                 {
588                     EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
589                     is_touch_blocked = 1;
590                 }
591                 rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
592 #endif
593                 setRotaryFlag = 1;
594                 LogMessageVerbSigSafe(X_INFO, 1, "[Rotary] OFM detent has been sent. setRotaryFlag=%d, setDetentFlag=%d, device name=%s \n", setRotaryFlag, setDetentFlag, dev->name);
595             }
596             else
597                 DetailDebugPrint(X_INFO, 1, "[Rotary] Hall ic detent has already been sent. setRotaryFlag=%d, setDetentFlag=%d \n", setRotaryFlag, setDetentFlag);
598
599             if (state == IDLE)
600             {
601                 if (angle_delta_cal > 0)
602                 {
603                     angle_delta_dir = 1;
604                 }
605                 else if (angle_delta_cal < 0)
606                 {
607                     angle_delta_dir = -1;
608                 }
609                 start_event_timer = TimerSet(start_event_timer, 0, START_TIMEOUT, RotaryReset, pInfo);
610                 DetailDebugPrint(X_INFO, 1, "[Detent] START! REL_Y = %d\n", event_time);
611                 state = MOVING;
612             }
613
614             if (angle_delta_dir == 1)
615                 angle_pos_sub_cal -= (DETENT_INTERVAL * detent_count);
616             else
617                 angle_pos_sub_cal += (DETENT_INTERVAL * detent_count);
618
619             DetailDebugPrint(X_INFO, 1, "[Detent] raw_X=%d, kernel_angle=%d, X=%d, angle=%d, time=%d, detent=%d, move_sum=%d\n",
620                     angle_delta_raw, angle_pos_raw, angle_delta_cal, angle_pos, event_time, detent_count, angle_pos_sub_cal);
621
622             if (angle_pos_sub_cal > DETENT_TIMEOUT_TOLERANCE)
623             {
624                 DetailDebugPrint(X_INFO, 1, "[Compensation] move_sum = %d -> 10\n", angle_pos_sub_cal);
625                 angle_pos_sub_cal = DETENT_TOLERANCE;
626             }
627             else if (angle_pos_sub_cal < -DETENT_TIMEOUT_TOLERANCE)
628             {
629                 DetailDebugPrint(X_INFO, 1, "[Compensation] move_sum = %d -> -10\n", angle_pos_sub_cal);
630                 angle_pos_sub_cal = -DETENT_TOLERANCE;
631             }
632
633             //detent timer
634             detent_event_timer = TimerSet(detent_event_timer, 0, DETENT_TIMEOUT, RotaryReset, pInfo);
635             if (start_event_timer)
636             {
637                 DetailDebugPrint(X_INFO, 1, "[Start_Timer_Delete]\n");
638                 start_event_timer_flag = DELETE_TIMER;
639             }
640             is_detent = 0; // reset detent flag
641         }
642         else // no detent
643         {
644             if (state == IDLE)
645             {
646                 valuator_mask_set(pEvdev->vals, REL_Z, NULL_DETENT);
647                 if (angle_pos_sub_cal > DETENT_TOLERANCE || angle_pos_sub_cal < -DETENT_TOLERANCE)
648                 {
649                     if (angle_delta_cal > 0)
650                     {
651                         angle_delta_dir = 1;
652                     }
653                     else if (angle_delta_cal < 0)
654                     {
655                         angle_delta_dir = -1;
656                     }
657                     start_event_timer = TimerSet(start_event_timer, 0, START_TIMEOUT, RotaryReset, pInfo);
658                     DetailDebugPrint(X_INFO, 1, "[Start] start tolerance = %d\n", angle_pos_sub_cal);
659                     state = MOVING;
660                 }
661                 else
662                 {
663                     if (angle_pos_sub_cal * angle_delta_cal <= 0)
664                     {
665                         DetailDebugPrint(X_INFO, 1, "[No Start] Direction changed. before=%d, current=%d\n", angle_pos_sub_cal, angle_delta_cal);
666                         angle_pos_sub_cal = angle_delta_cal;
667                     }
668                     else
669                         DetailDebugPrint(X_INFO, 1, "[No Start] No start tolerance = %d\n", angle_pos_sub_cal);
670                 }
671             }
672
673             if (state == MOVING)
674             {
675                 if ( (angle_delta_dir == 1 && angle_pos_sub_cal <= (return_tolerance*2)) ||
676                         (angle_delta_dir == -1 && angle_pos_sub_cal >= -(return_tolerance*2)) )
677                 {
678                     valuator_mask_set(pEvdev->vals, REL_X, 0);
679                     valuator_mask_set(pEvdev->vals, REL_Z, ZERO_DETENT);
680                     DetailDebugPrint(X_INFO, 1, "[Detent2] angle_delta_dir=%d, angle_pos_sub_cal=%d, return case%d\n",
681                             angle_delta_dir, angle_pos_sub_cal, (angle_delta_dir==1)?1:2);
682                     angle_delta_dir = 0;
683                     detent_sum++;
684                     return_state = 1;
685                 }
686                 else
687                 {
688                     valuator_mask_set(pEvdev->vals, REL_Z, NULL_DETENT);
689                     DetailDebugPrint(X_INFO, 1, "[No Detent1] raw_X=%d, kernel_angle=%d, X=%d, angle=%d, time=%d, detent=%d, move_sum=%d\n",
690                             angle_delta_raw, angle_pos_raw, angle_delta_cal, angle_pos, event_time, NULL_DETENT, angle_pos_sub_cal);
691                 }
692
693                 if (return_state)
694                 {
695                     if (start_event_timer)
696                     {
697                         DetailDebugPrint(X_INFO, 1, "[start_event_timer Cancel]\n");
698                         start_event_timer_flag = DELETE_TIMER;
699                     }
700
701                     detent_event_timer = TimerSet(detent_event_timer, 0, RETURN_TIMEOUT, RotaryReset, pInfo);
702
703                     return_state = 0;
704                     return_ignore_state = 1;
705                     return_ignore_angle = angle_pos_sub_cal;
706                 }
707             }
708         }
709     }
710 }
711
712 void EvdevRotaryInit(DeviceIntPtr device)
713 {
714     InputInfoPtr pInfo;
715     EvdevPtr pEvdev;
716
717     InputInfoPtr pInfoDetent = NULL;
718     EvdevPtr pEvdevDetent = NULL;
719     DeviceIntPtr dev;
720
721     pInfo = device->public.devicePrivate;
722     pEvdev = pInfo->private;
723     if (pEvdev->flags & EVDEV_OFM) {
724         pEvdev->extra_rel_post_ofm= EvdevRotaryProcessOfmEvent;
725
726         hw_rotary_max = pEvdev->HW_Calibration;
727         kernel_angle_step = ((double)SW_ROTARY_MAX/hw_rotary_max);
728         return_tolerance = ((10 * SW_ROTARY_MAX) / hw_rotary_max);
729
730         if (hasDetent)
731         {
732             for (dev = inputInfo.keyboard; dev; dev = dev->next)
733             {
734                 if (!strncmp(dev->name, "tizen_detent", strlen(dev->name)))
735                 {
736                     pInfoDetent = dev->public.devicePrivate;
737                     pEvdevDetent = pInfoDetent->private;
738                     break;
739                 }
740             }
741             pEvdevDetent->extra_rel_post_hallic = EvdevRotaryProcessLegacyHallIcEvent;
742             LogMessageVerbSigSafe(X_INFO, 1, "[EvdevRotaryInit][OFM+HALL] Detent device detected before rotary device. So, detent device call has been changed.\n");
743         }
744
745         hasRotary = OFM_DEVICE;
746
747         LogMessageVerbSigSafe(X_INFO, 1, "[Rotary Init] hw_rotary_max=%d, return_tolerance=%d, kernel_angle_step=%d\n", hw_rotary_max, return_tolerance, kernel_angle_step);
748     }
749
750     if (pEvdev->flags & EVDEV_HALLIC) {
751         if (hasRotary)
752         {
753             pEvdev->extra_rel_post_hallic = EvdevRotaryProcessLegacyHallIcEvent;
754             LogMessageVerbSigSafe(X_INFO, 1, "[EvdevRotaryInit][OFM+HALL] Rotary device detetced before detent device\n");
755         }
756         else
757         {
758             pEvdev->extra_rel_post_hallic = EvdevRotaryProcessHallIcEvent;
759             LogMessageVerbSigSafe(X_INFO, 1, "[EvdevRotaryInit][HALL] Detent device without rotary device.\n");
760         }
761         hasDetent = HALL_DEVICE;
762     }
763 }
764
765 void EvdevRotaryUnInit(EvdevPtr pEvdev)
766 {
767     if(!pEvdev)
768     {
769         LogMessageVerbSigSafe(X_ERROR, 1, "[EvdevRotaryUnInit] pEvdev not yet initialized.\n");
770         return;
771     }
772
773     if (pEvdev->flags & EVDEV_OFM)
774     {
775         TimerFree(rotary_frame_sync_timer);
776         rotary_frame_sync_timer = NULL;
777     }
778 }
779
780 #endif //_F_EVDEV_SUPPORT_ROTARY_