3 * xserver-xorg-input-evdev
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>
12 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
13 * Copyright © 2004-2008 Red Hat, Inc.
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
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.
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)
41 #ifdef _F_EVDEV_SUPPORT_ROTARY_
48 #include <evdev-properties.h>
50 #include <sys/types.h>
57 #include <xf86Xinput.h>
62 #define SW_ROTARY_MAX 3600 // Mathematical rotary angular position limit (i.e. 360) scaled by CALCULATOR_VALUE.
64 #define DETENT_TOLERANCE 20
65 #define DETENT_TIMEOUT_TOLERANCE 30
67 #define DETENT_TIMEOUT 500
68 #define START_TIMEOUT 2000
69 #define RETURN_TIMEOUT 200
72 #define CALCULATOR_VALUE 10 //for 3600-base angle
73 #define DETENT_INTERVAL 150
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
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
93 #define ENABLE_TIMER 0
94 #define DELETE_TIMER 1
96 //#define __DETAIL_DEBUG__
98 #ifdef __DETAIL_DEBUG__
99 #define DetailDebugPrint LogMessageVerbSigSafe
101 #define DetailDebugPrint(...)
104 static int hasRotary = NO_DEVICE;
105 static int hasDetent = NO_DEVICE;
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;
111 static OsTimerPtr detent_event_timer = NULL;
112 static OsTimerPtr start_event_timer = NULL;
113 static int start_event_timer_flag = ENABLE_TIMER;
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;
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;
133 static int detent_hall_ic = 0;
134 static int detent_hall_ic_prev = 0;
135 static int hall_ic_count = -1;
137 static int setRotaryFlag = 0;
138 static int setDetentFlag = 0;
140 #ifdef _F_GESTURE_EXTENSION_
142 #define ROTARY_FRAME_SYNC_TIMEOUT 200
143 #define ROTARY_FRAME_SYNC_TOLERANCE 30
145 static OsTimerPtr rotary_frame_sync_timer = NULL;
146 static unsigned char is_touch_blocked = 0;
148 extern void mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e);
149 void EvdevRotarySync(InputInfoPtr pInfo, MTSyncType sync)
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;
160 mieqEnqueue (pInfo->dev, (InternalEvent*)&event);
162 static CARD32 EvdevRotarySyncTimerFinish(OsTimerPtr timer, CARD32 time, pointer arg)
164 InputInfoPtr pInfo = (InputInfoPtr)arg;
166 if (is_touch_blocked == 0)
168 TimerCancel(rotary_frame_sync_timer);
172 DetailDebugPrint(X_INFO, 1, "[EvdevRotarySyncTimerFinish] Touch is freed from blocking.\n");
173 EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_END);
174 is_touch_blocked = 0;
181 ResetValues(OsTimerPtr timer, CARD32 time, pointer arg)
183 angle_pos_sub_cal = 0;
190 return_ignore_state = 0;
191 return_ignore_angle = 0;
193 return_ignore_reset_condition = 0;
199 DetailDebugPrint(X_INFO, 1, "[ResetValues] Reset all values!\n");
205 DeliverDetentEvent(InputInfoPtr pInfo, int type, int value)
207 EvdevPtr pEvdev = pInfo->private;
210 event_time = GetTimeInMillis();
212 valuator_mask_set(pEvdev->vals, REL_X, value);
213 valuator_mask_set(pEvdev->vals, REL_Y, event_time);
220 valuator_mask_set(pEvdev->vals, REL_Z, detent_type);
221 xf86PostMotionEventM(pInfo->dev, Relative, pEvdev->vals);
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);
228 RotaryReset(OsTimerPtr timer, CARD32 time, pointer arg)
230 InputInfoPtr pInfo = (InputInfoPtr)arg;
232 EvdevPtr pEvdev = pInfo->private;
234 if (start_event_timer_flag && (timer == start_event_timer))
236 start_event_timer_flag = ENABLE_TIMER;
237 TimerCancel(start_event_timer);
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)))
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);
246 ResetValues(NULL, 1, NULL);
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;
253 if (return_ignore_state == 1)
255 ResetValues(NULL, 1, NULL);
256 DetailDebugPrint(X_INFO, 1, "[Reset return ignore state] return_ignore_state=%d.\n", return_ignore_state);
261 DetailDebugPrint(X_INFO, 1, "[Reset] Stop between detents !\n");
263 if (detent_hall_ic > 0)
265 DetailDebugPrint(X_INFO, 1, "[Reset] Find hall ic event!Deliver detent event\n");
266 ResetValues(NULL, 1, NULL);
272 if (detent_event_timer)
274 TimerCancel(detent_event_timer);
280 static void EvdevRotaryProcessHallIcEvent(InputInfoPtr pInfo, int num_v, int first_v,
281 int v[MAX_VALUATORS])
283 EvdevPtr pEvdev = pInfo->private;
284 int detent_count = 0;
287 event_time = GetTimeInMillis();
289 detent_hall_ic = valuator_mask_get(pEvdev->vals, REL_Z);
290 switch(detent_hall_ic)
292 case HALLIC_DETENT_RIGHT:
293 detent_count = RIGHT_DETENT;
295 case HALLIC_DETENT_LEFT:
296 detent_count = LEFT_DETENT;
298 case HALLIC_MOVE_OUT:
299 detent_count = ZERO_DETENT;
303 detent_count = ZERO_DETENT;
306 LogMessageVerbSigSafe(X_WARNING, 1, "[EvdevRotaryProcessHallIcEvent] Unknown Hall IC event! assuming HALLIC_MOVE_IN.\n");
307 detent_count = ZERO_DETENT;
310 DetailDebugPrint(X_INFO, 1, "[HALL Only] REL_Z=%d, detent_count=%d, time=%d\n", detent_hall_ic, detent_count, event_time);
312 #ifdef _F_GESTURE_EXTENSION_
315 DetailDebugPrint(X_INFO, 1, "[EvdevRotaryProcessHallIcEvent] Rotary is moving...touch is blocked!\n");
316 if(is_touch_blocked == 0)
318 EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
319 is_touch_blocked = 1;
321 rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
326 if(!(DPMSPowerLevel == DPMSModeOff || DPMSPowerLevel == DPMSModeSuspend))
328 #ifdef _F_GESTURE_EXTENSION_
329 if(is_touch_blocked == 1)
331 EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_END);
332 is_touch_blocked = 0;
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);
343 DetailDebugPrint(X_INFO, 1, "[No detent] DPMS off or suspend.\n");
349 static void EvdevRotaryProcessLegacyHallIcEvent(InputInfoPtr pInfo, int num_v, int first_v,
350 int v[MAX_VALUATORS])
352 EvdevPtr pEvdev = pInfo->private;
353 int detent_count = 0;
355 event_time = GetTimeInMillis();
357 detent_hall_ic = valuator_mask_get(pEvdev->vals, REL_Z);
359 valuator_mask_set(pEvdev->vals, REL_X, NO_VALUE);
360 valuator_mask_set(pEvdev->vals, REL_Y, event_time);
362 if (!detent_hall_ic_prev)
364 if (angle_pos_raw > 0)
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);
369 else if (angle_pos_raw < 0)
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);
379 switch(detent_hall_ic)
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;
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;
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;
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);
406 valuator_mask_set(pEvdev->vals, REL_Z, detent_count);
408 if((!(DPMSPowerLevel == DPMSModeOff || DPMSPowerLevel == DPMSModeSuspend)) && (setRotaryFlag == 0))
410 xf86PostMotionEventM(pInfo->dev, Relative, pEvdev->vals);
411 #ifdef _F_GESTURE_EXTENSION_
412 if(is_touch_blocked == 0)
414 EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
415 is_touch_blocked = 1;
417 rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
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);
423 DetailDebugPrint(X_INFO, 1, "[Rotary] DPMS off or suspend or rotary detent has already been sent. setRotaryFlag=%d, setDetentFlag=%d \n", setRotaryFlag, setDetentFlag);
425 detent_hall_ic_prev = detent_hall_ic;
432 static void EvdevRotaryProcessOfmEvent(InputInfoPtr pInfo, int num_v, int first_v,
433 int v[MAX_VALUATORS])
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
441 EvdevPtr pEvdev = pInfo->private;
444 InputInfoPtr pInfoDetent;
445 EvdevPtr pEvdevDetent;
447 event_time = GetTimeInMillis();
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);
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;
456 angle_pos_sub_cal += angle_delta_cal;
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;
464 if (hall_ic_count >= 0)
467 if (hall_ic_count > 2)
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);
476 if (ignore_state == 1)
478 ignore_angle += angle_delta_cal;
480 if (ignore_angle * angle_delta_cal < 0)
482 if ((ignore_angle < DETENT_INTERVAL - DETENT_TOLERANCE) && (ignore_angle > -DETENT_INTERVAL + DETENT_TOLERANCE))
484 DetailDebugPrint(X_INFO, 1, "[Opposite direction] ignore_angle=%d, angle_delta_cal=%d, Reset!!\n", ignore_angle, angle_delta_cal);
488 detent_event_timer = TimerSet(detent_event_timer, 0, 1, ResetValues, NULL);
492 DetailDebugPrint(X_INFO, 1, "[Opposite direction, inside threshold] ignore_angle=%d, angle_delta_cal=%d, No Reset.\n", ignore_angle, angle_delta_cal);
498 if ((ignore_angle >= DETENT_INTERVAL + DETENT_TIMEOUT_TOLERANCE) || (ignore_angle <= -DETENT_INTERVAL - DETENT_TIMEOUT_TOLERANCE))
500 DetailDebugPrint(X_INFO, 1, "[No Deliver] ignore_angle=%d, Reset!!\n", ignore_angle);
504 detent_event_timer = TimerSet(detent_event_timer, 0, 1, ResetValues, NULL);
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);
513 if (return_ignore_state == 1)
515 return_ignore_angle += angle_delta_cal;
517 if ((return_ignore_angle < DETENT_TIMEOUT_TOLERANCE) && (return_ignore_angle > -DETENT_TIMEOUT_TOLERANCE))
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);
523 return_ignore_reset_condition = 1;
526 if( angle_delta_cal == 0 )
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);
530 else // angle_delta_cal != 0
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))
536 is_detent = 1; // Set detent flag
538 if( angle_pos_sub_cal >= DETENT_INTERVAL ) // right direction, NO need to consider tolerance
540 detent_count = angle_pos_sub_cal / DETENT_INTERVAL;
542 else if( angle_pos_sub_cal <= -DETENT_INTERVAL ) // left direction, NO need to consider tolerance
544 detent_count = -angle_pos_sub_cal / DETENT_INTERVAL;
546 else // right or left direction, NEED to consider tolerance!
550 detent_sum += detent_count;
554 valuator_mask_set(pEvdev->vals, REL_X, angle_delta_cal);
555 valuator_mask_set(pEvdev->vals, REL_Y, event_time);
557 if( is_detent == 1 ) // detent
560 ignore_angle = angle_pos_sub_cal % DETENT_INTERVAL;
564 if (angle_pos_sub_cal > 0)
565 detent_count = RIGHT_DETENT;
567 detent_count = LEFT_DETENT;
571 for (dev = inputInfo.keyboard; dev; dev = dev->next)
573 if (!strncmp(dev->name, "tizen_detent", strlen(dev->name)))
575 pInfoDetent = dev->public.devicePrivate;
576 pEvdevDetent = pInfoDetent->private;
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)
588 EvdevRotarySync(pInfo, ROTARY_FRAME_SYNC_BEGIN);
589 is_touch_blocked = 1;
591 rotary_frame_sync_timer = TimerSet(rotary_frame_sync_timer, 0, ROTARY_FRAME_SYNC_TIMEOUT, EvdevRotarySyncTimerFinish, pInfo);
594 LogMessageVerbSigSafe(X_INFO, 1, "[Rotary] OFM detent has been sent. setRotaryFlag=%d, setDetentFlag=%d, device name=%s \n", setRotaryFlag, setDetentFlag, dev->name);
597 DetailDebugPrint(X_INFO, 1, "[Rotary] Hall ic detent has already been sent. setRotaryFlag=%d, setDetentFlag=%d \n", setRotaryFlag, setDetentFlag);
601 if (angle_delta_cal > 0)
605 else if (angle_delta_cal < 0)
607 angle_delta_dir = -1;
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);
614 if (angle_delta_dir == 1)
615 angle_pos_sub_cal -= (DETENT_INTERVAL * detent_count);
617 angle_pos_sub_cal += (DETENT_INTERVAL * detent_count);
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);
622 if (angle_pos_sub_cal > DETENT_TIMEOUT_TOLERANCE)
624 DetailDebugPrint(X_INFO, 1, "[Compensation] move_sum = %d -> 10\n", angle_pos_sub_cal);
625 angle_pos_sub_cal = DETENT_TOLERANCE;
627 else if (angle_pos_sub_cal < -DETENT_TIMEOUT_TOLERANCE)
629 DetailDebugPrint(X_INFO, 1, "[Compensation] move_sum = %d -> -10\n", angle_pos_sub_cal);
630 angle_pos_sub_cal = -DETENT_TOLERANCE;
634 detent_event_timer = TimerSet(detent_event_timer, 0, DETENT_TIMEOUT, RotaryReset, pInfo);
635 if (start_event_timer)
637 DetailDebugPrint(X_INFO, 1, "[Start_Timer_Delete]\n");
638 start_event_timer_flag = DELETE_TIMER;
640 is_detent = 0; // reset detent flag
646 valuator_mask_set(pEvdev->vals, REL_Z, NULL_DETENT);
647 if (angle_pos_sub_cal > DETENT_TOLERANCE || angle_pos_sub_cal < -DETENT_TOLERANCE)
649 if (angle_delta_cal > 0)
653 else if (angle_delta_cal < 0)
655 angle_delta_dir = -1;
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);
663 if (angle_pos_sub_cal * angle_delta_cal <= 0)
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;
669 DetailDebugPrint(X_INFO, 1, "[No Start] No start tolerance = %d\n", angle_pos_sub_cal);
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)) )
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);
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);
695 if (start_event_timer)
697 DetailDebugPrint(X_INFO, 1, "[start_event_timer Cancel]\n");
698 start_event_timer_flag = DELETE_TIMER;
701 detent_event_timer = TimerSet(detent_event_timer, 0, RETURN_TIMEOUT, RotaryReset, pInfo);
704 return_ignore_state = 1;
705 return_ignore_angle = angle_pos_sub_cal;
712 void EvdevRotaryInit(DeviceIntPtr device)
717 InputInfoPtr pInfoDetent = NULL;
718 EvdevPtr pEvdevDetent = NULL;
721 pInfo = device->public.devicePrivate;
722 pEvdev = pInfo->private;
723 if (pEvdev->flags & EVDEV_OFM) {
724 pEvdev->extra_rel_post_ofm= EvdevRotaryProcessOfmEvent;
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);
732 for (dev = inputInfo.keyboard; dev; dev = dev->next)
734 if (!strncmp(dev->name, "tizen_detent", strlen(dev->name)))
736 pInfoDetent = dev->public.devicePrivate;
737 pEvdevDetent = pInfoDetent->private;
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");
745 hasRotary = OFM_DEVICE;
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);
750 if (pEvdev->flags & EVDEV_HALLIC) {
753 pEvdev->extra_rel_post_hallic = EvdevRotaryProcessLegacyHallIcEvent;
754 LogMessageVerbSigSafe(X_INFO, 1, "[EvdevRotaryInit][OFM+HALL] Rotary device detetced before detent device\n");
758 pEvdev->extra_rel_post_hallic = EvdevRotaryProcessHallIcEvent;
759 LogMessageVerbSigSafe(X_INFO, 1, "[EvdevRotaryInit][HALL] Detent device without rotary device.\n");
761 hasDetent = HALL_DEVICE;
765 void EvdevRotaryUnInit(EvdevPtr pEvdev)
769 LogMessageVerbSigSafe(X_ERROR, 1, "[EvdevRotaryUnInit] pEvdev not yet initialized.\n");
773 if (pEvdev->flags & EVDEV_OFM)
775 TimerFree(rotary_frame_sync_timer);
776 rotary_frame_sync_timer = NULL;
780 #endif //_F_EVDEV_SUPPORT_ROTARY_