evded: timestamping with monotonic time (+ configuration ioctl)
PATCH 1/1 evded: timestamping with monotonic time (+ configuration ioctl)
For my modification of XFree86 keyboard event handling I need to detect *duration* of key presses, i.e. difference in time between 2 input events.
Evdev, in current version, timestamps each event with do_gettimeofday(). In presence of adjustements to timeofday the difference/duration information is damaged.
I would like to read the events timestamped withdo_posix_clock_monotonic_gettime() time.
I have prepared a patch, which provides an IOCTL call with which a reader can request this monotonic timestamp. The default behaviour remains unchanged (I think useless).
What i am not sure about:
* evdev builds as module, so do_posix_clock_monotonic_gettime is needed exported... so my patch adds EXPORT_SYMBOL_GPL(do_posix_clock_monotonic_gettime) in kernel/posix-timers.c.
* _IOW macro to declare the ioctl number
I took just a successor of the highest pre-existant number.
* I don't know how interrupt handlers preempt one another. So, in my attempt to attain the most precise timestamp, I would like the interrupt routine to ask for the timestamp as soon as possible. I could prepare another patch, which adds to each "struct input_dev" a slot where the timestamp is stored at the beginning of the interrupt routine. Evdev then uses such timestamp, if the lower-level driver provides it.
drivers/input/evdev.c +41 -2
@@ -38,6 +38,7 @@struct input_event buffer[EVDEV_BUFFER_SIZE ];int head;int tail; +int time_kind;/* which time to use for the timestamps. Monotonic or timeofday */ struct fasync_struct *fasync;struct evdev *evdev;struct list_head node;
@@ -45,15 +46,37 @@static struct evdev *evdev_table[EVDEV_MINORS ]; +static inline +void +mem_copy_time (struct timeval *a,struct timeval * b) +{ +memcpy (a, b,sizeof (struct timeval )); +} +static void evdev_event (struct input_handle *handle,unsigned int type,unsigned int code,int value) {struct evdev *evdev = handle->private;struct evdev_list *list; +struct timeval mtv, dtv; +/* `do_posix_clock_monotonic_gettime' delivers a different struct, +* but i do the conversion immediately, and once. */ +struct timespec mts; + +do_posix_clock_monotonic_gettime (&mts); + mtv.tv_sec = mts.tv_sec; + mtv.tv_usec = mts.tv_nsec /1000 ;/* should I >> 10 ? */ + +do_gettimeofday (&dtv);/* for backward compatibility: */ +if (evdev->grab) { list = evdev->grab; -do_gettimeofday (&list->buffer[list->head].time); +if (list->time_kind ==EV_USE_DAY_TIME ) +mem_copy_time (&list->buffer[list->head].time,&dtv); +else +mem_copy_time (&list->buffer[list->head].time,&mtv); + list->buffer[list->head].type = type; list->buffer[list->head].code = code; list->buffer[list->head].value = value;
@@ -63,7 +86,11 @@ }else list_for_each_entry (list, &evdev->list, node) { -do_gettimeofday (&list->buffer[list->head].time); +if (list->time_kind ==EV_USE_DAY_TIME ) +mem_copy_time (&list->buffer[list->head].time,&dtv); +else +mem_copy_time (&list->buffer[list->head].time,&mtv); + list->buffer[list->head].type = type; list->buffer[list->head].code = code; list->buffer[list->head].value = value;
@@ -135,6 +162,7 @@return -ENOMEM ;memset (list,0 ,sizeof (struct evdev_list )); + list->time_kind =EV_USE_DAY_TIME ;/* for backward compatibility! */ list->evdev = evdev_table[i];list_add_tail (&list->node, &evdev_table[i]->list); file->private_data = list;
@@ -371,6 +399,17 @@ evdev->grab =NULL ;return 0 ; } +case EVIOCTIME : +switch (arg) { +case EV_USE_MONOTONIC_TIME : + list->time_kind =EV_USE_MONOTONIC_TIME ; +return 0 ; +case EV_USE_DAY_TIME : + list->time_kind =EV_USE_DAY_TIME ; +return 0 ; +default : +return -EINVAL ; + }default :
include/linux/input.h +9 -0
@@ -78,6 +78,15 @@#define EVIOCGRAB _IOW('E', 0x90, int)/* Grab/Release device */ +#define EVIOCTIME _IOW('E', 0x91, int)/* choose what kind of time to use for timestamps */ + +/* +* Time used to timestamp +*/ +#define EV_USE_MONOTONIC_TIME 0 +#define EV_USE_DAY_TIME 1 + +/* * Event types */
kernel/posix-timers.c +1 -0
@@ -1223,6 +1223,7 @@ {return do_posix_clock_monotonic_get (CLOCK_MONOTONIC , tp); } +EXPORT_SYMBOL_GPL (do_posix_clock_monotonic_gettime);int do_posix_clock_nosettime (clockid_t clockid,struct timespec *tp) {