From: Henrik Rydberg <hidden> Date: 2012-08-12 21:39:27
Dmitry, Jiri,
Here is the tentative patchset planned for 3.7. It touches both the
Input and HID subsystems, so I decided to send it to both of you at
once. How to distribute the patches can be decided later.
The gist of the set is in-kernel tracking and latency. As I started
measuring irqsoff times, I realized we did quite poorly in that
department. Consequently, some of the patches are general and
substantial speedups which ought to make everybody happy.
Patches 1-6 rearranges the input core to send packets of events
instead of one event at a time.
Patch 7 implements this in evdev.
Patches 8-11 incorporate more duplicated code into mt core, and
implements a simple - but correct - form of tracking. Earlier variants
have either been complex, approximate or slow. This one is only about
50 lines of code and fast enough to handle ten fingers in interrupt
context.
Patches 12-15 convert bcm5974 to MT-B.
Patch 16 is janitory.
Patch 17 provides a substantial latency improvement on simple key
strokes.
Patches 18-19 are for hid-multitouch, reducing memory and simplifying
the driver.
Thanks,
Henrik
Henrik Rydberg (19):
Input: Break out MT data
Input: Improve the events-per-packet estimate
Input: Remove redundant packet estimates
Input: Make sure we follow all EV_KEY events
Input: Move autorepeat to the event-passing phase
Input: Send events one packet at a time
Input: evdev - Add the events() callback
Input: MT - Add flags to input_mt_init_slots()
Input: MT - Handle frame synchronization in core
Input: MT - Add in-kernel tracking
Input: MT - Add slot assignment by id
Input: bcm5974 - Preparatory renames
Input: bcm5974 - Drop pressure and width emulation
Input: bcm5974 - Drop the logical dimensions
Input: bcm5974 - Convert to MT-B
HID: hid-multitouch: Remove misleading null test
HID: Only dump input if someone is listening
HID: Add an input configured notification callback
HID: multitouch: Remove the redundant touch state
drivers/hid/hid-core.c | 3 +-
drivers/hid/hid-input.c | 15 +-
drivers/hid/hid-magicmouse.c | 4 +-
drivers/hid/hid-multitouch.c | 172 ++++++++----------
drivers/input/evdev.c | 78 +++++---
drivers/input/input-mt.c | 297 ++++++++++++++++++++++++++++---
drivers/input/input.c | 252 +++++++++++++++-----------
drivers/input/misc/uinput.c | 2 +-
drivers/input/mouse/alps.c | 2 +-
drivers/input/mouse/bcm5974.c | 274 ++++++++++------------------
drivers/input/mouse/elantech.c | 4 +-
drivers/input/mouse/sentelic.c | 2 +-
drivers/input/mouse/synaptics.c | 4 +-
drivers/input/tablet/wacom_wac.c | 6 +-
drivers/input/touchscreen/atmel_mxt_ts.c | 2 +-
drivers/input/touchscreen/cyttsp_core.c | 2 +-
drivers/input/touchscreen/edt-ft5x06.c | 2 +-
drivers/input/touchscreen/egalax_ts.c | 2 +-
drivers/input/touchscreen/ili210x.c | 2 +-
drivers/input/touchscreen/mms114.c | 2 +-
drivers/input/touchscreen/penmount.c | 2 +-
drivers/input/touchscreen/wacom_w8001.c | 2 +-
include/linux/hid.h | 3 +
include/linux/input.h | 35 ++--
include/linux/input/mt.h | 53 +++++-
25 files changed, 744 insertions(+), 478 deletions(-)
--
1.7.11.4
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:31
Move all MT-related things to a separate place. This saves some
bytes for non-mt input devices, and prepares for new MT features.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/evdev.c | 10 ++++++----
drivers/input/input-mt.c | 47 +++++++++++++++++++++++++++--------------------
drivers/input/input.c | 9 ++++-----
include/linux/input.h | 9 ++-------
include/linux/input/mt.h | 16 ++++++++++++++--
5 files changed, 53 insertions(+), 38 deletions(-)
@@ -27,26 +27,28 @@*/intinput_mt_init_slots(structinput_dev*dev,unsignedintnum_slots){+structinput_mt*mt=dev->mt;inti;if(!num_slots)return0;-if(dev->mt)-returndev->mtsize!=num_slots?-EINVAL:0;+if(mt)+returnmt->num_slots!=num_slots?-EINVAL:0;-dev->mt=kcalloc(num_slots,sizeof(structinput_mt_slot),GFP_KERNEL);-if(!dev->mt)+mt=kzalloc(sizeof(*mt)+num_slots*sizeof(*mt->slots),GFP_KERNEL);+if(!mt)return-ENOMEM;-dev->mtsize=num_slots;+mt->num_slots=num_slots;input_set_abs_params(dev,ABS_MT_SLOT,0,num_slots-1,0,0);input_set_abs_params(dev,ABS_MT_TRACKING_ID,0,TRKID_MAX,0,0);input_set_events_per_packet(dev,6*num_slots);/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)-input_mt_set_value(&dev->mt[i],ABS_MT_TRACKING_ID,-1);+input_mt_set_value(&mt->slots[i],ABS_MT_TRACKING_ID,-1);+dev->mt=mt;return0;}EXPORT_SYMBOL(input_mt_init_slots);
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:33
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
@@ -1777,6 +1777,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)if(test_bit(i,dev->relbit))events++;+/* Make room for KEY and MSC events */+events+=7;+returnevents;}
@@ -1815,6 +1818,7 @@ int input_register_device(struct input_dev *dev){staticatomic_tinput_no=ATOMIC_INIT(0);structinput_handler*handler;+unsignedintpacket_size;constchar*path;interror;
@@ -1827,9 +1831,9 @@ int input_register_device(struct input_dev *dev)/* Make sure that bitmasks not mentioned in dev->evbit are clean. */input_cleanse_bitmasks(dev);-if(!dev->hint_events_per_packet)-dev->hint_events_per_packet=-input_estimate_events_per_packet(dev);+packet_size=input_estimate_events_per_packet(dev);+if(dev->hint_events_per_packet<packet_size)+dev->hint_events_per_packet=packet_size;/**Ifdelayandperiodarepre-setbythedriver,thenautorepeating
@@ -911,10 +911,6 @@ mapped:input_abs_set_res(input,usage->code,hidinput_calc_abs_res(field,usage->code));--/* use a larger default input buffer for MT devices */-if(usage->code==ABS_MT_POSITION_X&&input->hint_events_per_packet==0)-input_set_events_per_packet(input,60);}if(usage->type==EV_ABS&&
@@ -42,7 +42,6 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)mt->num_slots=num_slots;input_set_abs_params(dev,ABS_MT_SLOT,0,num_slots-1,0,0);input_set_abs_params(dev,ABS_MT_TRACKING_ID,0,TRKID_MAX,0,0);-input_set_events_per_packet(dev,6*num_slots);/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:39
For some EV_KEY types, sending a larger-than-one value causes the
input state to oscillate. This patch makes sure this cannot happen,
clearing up the autorepeat bypass logic in the process.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:42
Preparing to split event filtering and event passing, move the
autorepeat function to the point where the event is actually passed.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 46 +++++++++++++++++++++++++---------------------
1 file changed, 25 insertions(+), 21 deletions(-)
@@ -69,6 +69,22 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)returnvalue;}+staticvoidinput_start_autorepeat(structinput_dev*dev,intcode)+{+if(test_bit(EV_REP,dev->evbit)&&+dev->rep[REP_PERIOD]&&dev->rep[REP_DELAY]&&+dev->timer.data){+dev->repeat_key=code;+mod_timer(&dev->timer,+jiffies+msecs_to_jiffies(dev->rep[REP_DELAY]));+}+}++staticvoidinput_stop_autorepeat(structinput_dev*dev)+{+del_timer(&dev->timer);+}+/**Passeventfirstthroughallfiltersandthen,ifeventhasnotbeen*filteredout,throughallopenhandles.Thisfunctioniscalledwith
@@ -105,6 +121,15 @@ static void input_pass_event(struct input_dev *dev,}rcu_read_unlock();++/* trigger auto repeat for key events */+if(type==EV_KEY&&value!=2){+if(value)+input_start_autorepeat(dev,code);+else+input_stop_autorepeat(dev);+}+}/*
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:44
On heavy event loads, such as a multitouch driver, the irqsoff latency
can be as high as 250 us. By accumulating a frame worth of data
before passing it on, the latency can be dramatically reduced. As a
side effect, the special EV_SYN handling can be removed, since the
frame is now atomic.
This patch adds the events() handler callback and uses it if it
exists. The latency is improved by 50 us even without the callback.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input-mt.c | 3 +-
drivers/input/input.c | 187 ++++++++++++++++++++++++++++-------------------
include/linux/input.h | 26 +++++--
3 files changed, 132 insertions(+), 84 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:45
By sending a full frame of events at the same time, the irqsoff
latency at heavy load is brought down from 200 us to 100 us.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/evdev.c | 68 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 47 insertions(+), 21 deletions(-)
@@ -54,16 +54,9 @@ struct evdev_client {staticstructevdev*evdev_table[EVDEV_MINORS];staticDEFINE_MUTEX(evdev_table_mutex);-staticvoidevdev_pass_event(structevdev_client*client,-structinput_event*event,-ktime_tmono,ktime_treal)+staticvoid__pass_event(structevdev_client*client,+conststructinput_event*event){-event->time=ktime_to_timeval(client->clkid==CLOCK_MONOTONIC?-mono:real);--/* Interrupts are disabled, just acquire the lock. */-spin_lock(&client->buffer_lock);-client->buffer[client->head++]=*event;client->head&=client->bufsize-1;
@@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client,client->packet_head=client->head;kill_fasync(&client->fasync,SIGIO,POLL_IN);}+}++staticvoidevdev_pass_values(structevdev_client*client,+conststructinput_value*vals,size_tcount,+ktime_tmono,ktime_treal)+{+structevdev*evdev=client->evdev;+conststructinput_value*v;+structinput_eventevent;+boolwakeup=false;++event.time=ktime_to_timeval(client->clkid==CLOCK_MONOTONIC?+mono:real);++/* Interrupts are disabled, just acquire the lock. */+spin_lock(&client->buffer_lock);++for(v=vals;v!=vals+count;v++){+event.type=v->type;+event.code=v->code;+event.value=v->value;+__pass_event(client,&event);+if(v->type==EV_SYN&&v->code==SYN_REPORT)+wakeup=true;+}spin_unlock(&client->buffer_lock);++if(wakeup)+wake_up_interruptible(&evdev->wait);}/*-*Passincomingeventtoallconnectedclients.+*Passincomingeventstoallconnectedclients.*/-staticvoidevdev_event(structinput_handle*handle,-unsignedinttype,unsignedintcode,intvalue)+staticvoidevdev_events(structinput_handle*handle,+conststructinput_value*vals,size_tcount){structevdev*evdev=handle->private;structevdev_client*client;-structinput_eventevent;ktime_ttime_mono,time_real;time_mono=ktime_get();time_real=ktime_sub(time_mono,ktime_get_monotonic_offset());-event.type=type;-event.code=code;-event.value=value;-rcu_read_lock();client=rcu_dereference(evdev->grab);if(client)-evdev_pass_event(client,&event,time_mono,time_real);+evdev_pass_values(client,vals,count,time_mono,time_real);elselist_for_each_entry_rcu(client,&evdev->client_list,node)-evdev_pass_event(client,&event,time_mono,time_real);+evdev_pass_values(client,vals,count,+time_mono,time_real);rcu_read_unlock();+}-if(type==EV_SYN&&code==SYN_REPORT)-wake_up_interruptible(&evdev->wait);+/*+*Passincomingeventtoallconnectedclients.+*/+staticvoidevdev_event(structinput_handle*handle,+unsignedinttype,unsignedintcode,intvalue)+{+structinput_valuevals[]={{type,code,value}};++evdev_events(handle,vals,1);}staticintevdev_fasync(intfd,structfile*file,inton)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:47
With the INPUT_MT_TRACK flag set, the function input_mt_assign_slots()
can be used to match a new set of contacts against the currently used
slots. The algorithm used is based on Lagrange relaxation, and performs
very well in practice; slower than mtdev for a few corner cases, but
faster in most commonly occuring cases.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input-mt.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/input/mt.h | 21 +++++++
2 files changed, 163 insertions(+), 2 deletions(-)
@@ -46,7 +46,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,mt=kzalloc(sizeof(*mt)+num_slots*sizeof(*mt->slots),GFP_KERNEL);if(!mt)-return-ENOMEM;+gotoerr_mem;mt->num_slots=num_slots;mt->flags=flags;
@@ -74,6 +74,12 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,}if(flags&INPUT_MT_DIRECT)__set_bit(INPUT_PROP_DIRECT,dev->propbit);+if(flags&INPUT_MT_TRACK){+unsignedintn2=num_slots*num_slots;+mt->red=kcalloc(n2,sizeof(*mt->red),GFP_KERNEL);+if(!mt->red)+gotoerr_mem;+}/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)
@@ -81,6 +87,9 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,dev->mt=mt;return0;+err_mem:+kfree(mt);+return-ENOMEM;}EXPORT_SYMBOL(input_mt_init_slots);
@@ -18,6 +18,8 @@#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */+#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */+/***structinput_mt_slot-representsthestateofaninputMTslot*@abs:holdscurrentvaluesofABS_MTaxesforthisslot
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:49
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input-mt.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++--
include/linux/input/mt.h | 9 ++++++
2 files changed, 81 insertions(+), 2 deletions(-)
@@ -45,6 +53,28 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,input_set_abs_params(dev,ABS_MT_SLOT,0,num_slots-1,0,0);input_set_abs_params(dev,ABS_MT_TRACKING_ID,0,TRKID_MAX,0,0);+if(flags&(INPUT_MT_POINTER|INPUT_MT_DIRECT)){+__set_bit(EV_KEY,dev->evbit);+__set_bit(BTN_TOUCH,dev->keybit);++copy_abs(dev,ABS_X,ABS_MT_POSITION_X);+copy_abs(dev,ABS_Y,ABS_MT_POSITION_Y);+copy_abs(dev,ABS_PRESSURE,ABS_MT_PRESSURE);+}+if(flags&INPUT_MT_POINTER){+__set_bit(BTN_TOOL_FINGER,dev->keybit);+__set_bit(BTN_TOOL_DOUBLETAP,dev->keybit);+if(num_slots>=3)+__set_bit(BTN_TOOL_TRIPLETAP,dev->keybit);+if(num_slots>=4)+__set_bit(BTN_TOOL_QUADTAP,dev->keybit);+if(num_slots>=5)+__set_bit(BTN_TOOL_QUINTTAP,dev->keybit);+__set_bit(INPUT_PROP_POINTER,dev->propbit);+}+if(flags&INPUT_MT_DIRECT)+__set_bit(INPUT_PROP_DIRECT,dev->propbit);+/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)input_mt_set_value(&mt->slots[i],ABS_MT_TRACKING_ID,-1);
@@ -15,12 +15,17 @@#define TRKID_MAX 0xffff+#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */+#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */+#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame *//***structinput_mt_slot-representsthestateofaninputMTslot*@abs:holdscurrentvaluesofABS_MTaxesforthisslot+*@frame:lastframeatwhichinput_mt_report_slot_state()wascalled*/structinput_mt_slot{intabs[ABS_MT_LAST-ABS_MT_FIRST+1];+unsignedintframe;};/**
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:50
Some drivers produce their own tracking ids, which needs to be mapped
to slots. This patch provides that function.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input-mt.c | 30 ++++++++++++++++++++++++++++++
include/linux/input/mt.h | 2 ++
2 files changed, 32 insertions(+)
@@ -387,3 +387,33 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots,return0;}EXPORT_SYMBOL(input_mt_assign_slots);++/**+*input_mt_assign_slot_by_id()-returnmatchingslot+*@dev:inputdevicewithallocatedMTslots+*@id:thesoughttrackingid+*+*Returnstheslotofthegiventrackingid,ifitexists.Otherwise,+*thefirstunusedslotisreturned.+*+*Ifnoavailableslotcanbefound,-1isreturned.+*/+intinput_mt_assign_slot_by_id(structinput_dev*dev,intid)+{+structinput_mt*mt=dev->mt;+structinput_mt_slot*s;++if(!mt)+return-1;++for(s=mt->slots;s!=mt->slots+mt->num_slots;s++)+if(input_mt_get_value(s,ABS_MT_TRACKING_ID)==id)+returns-mt->slots;++for(s=mt->slots;s!=mt->slots+mt->num_slots;s++)+if(!input_mt_is_active(s))+returns-mt->slots;++return-1;+}+EXPORT_SYMBOL(input_mt_assign_slot_by_id);
@@ -1152,7 +1152,7 @@ static int __devinit mxt_probe(struct i2c_client *client,/* For multi touch */num_mt_slots=data->T9_reportid_max-data->T9_reportid_min+1;-error=input_mt_init_slots(input_dev,num_mt_slots);+error=input_mt_init_slots(input_dev,num_mt_slots,0);if(error)gotoerr_free_object;input_set_abs_params(input_dev,ABS_MT_TOUCH_MAJOR,
@@ -404,7 +404,7 @@ static int __devinit mms114_probe(struct i2c_client *client,input_set_abs_params(input_dev,ABS_Y,0,data->pdata->y_size,0,0);/* For multi touch */-input_mt_init_slots(input_dev,MMS114_MAX_TOUCH);+input_mt_init_slots(input_dev,MMS114_MAX_TOUCH,0);input_set_abs_params(input_dev,ABS_MT_TOUCH_MAJOR,0,MMS114_MAX_AREA,0,0);input_set_abs_params(input_dev,ABS_MT_POSITION_X,
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:53
Rename touch properties to match established nomenclature, and define
the maximum number of fingers.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/mouse/bcm5974.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:55
The ABS_PRESSURE and ABS_WIDTH have special scales, and were initially
added solely for thumb and palm recognition in the synaptics driver.
This never really get used, however, and userspace quickly moved to
MT solutions instead. This patch drops the unused events.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/mouse/bcm5974.c | 26 +++++---------------------
1 file changed, 5 insertions(+), 21 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:56
The logical scale was previously used to produce special width values
to userspace, and its only present use is to put "pressure" hysteresis
on a common scale. However, bcm5974 trackpads are very accurate and
work well without hysteresis.
This patch simplifies the driver and device data by removing the logical
scale altogether. While at it, the fake pressure range is replaced by the
orientation range, which will be used in a subsequent patch.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/mouse/bcm5974.c | 193 ++++++++++++++++--------------------------
1 file changed, 75 insertions(+), 118 deletions(-)
@@ -397,18 +385,11 @@ static inline int raw2int(__le16 x)return(signedshort)le16_to_cpu(x);}-/* scale device data to logical dimensions (asserts devmin < devmax) */-staticinlineintint2scale(conststructbcm5974_param*p,intx)-{-returnx*p->dim/(p->devmax-p->devmin);-}--/* all logical value ranges are [0,dim). */-staticinlineintint2bound(conststructbcm5974_param*p,intx)+staticvoidset_abs(structinput_dev*input,unsignedintcode,+conststructbcm5974_param*p){-ints=int2scale(p,x);--returnclamp_val(s,0,p->dim-1);+intfuzz=p->snratio?(p->max-p->min)/p->snratio:0;+input_set_abs_params(input,code,p->min,p->max,fuzz,0);}/* setup which logical events to report */
@@ -417,30 +398,21 @@ static void setup_events_to_report(struct input_dev *input_dev,{__set_bit(EV_ABS,input_dev->evbit);-input_set_abs_params(input_dev,ABS_X,-0,cfg->x.dim,cfg->x.fuzz,0);-input_set_abs_params(input_dev,ABS_Y,-0,cfg->y.dim,cfg->y.fuzz,0);+/* pointer emulation */+set_abs(input_dev,ABS_X,&cfg->w);+set_abs(input_dev,ABS_Y,&cfg->w);/* finger touch area */-input_set_abs_params(input_dev,ABS_MT_TOUCH_MAJOR,-cfg->w.devmin,cfg->w.devmax,0,0);-input_set_abs_params(input_dev,ABS_MT_TOUCH_MINOR,-cfg->w.devmin,cfg->w.devmax,0,0);+set_abs(input_dev,ABS_MT_TOUCH_MAJOR,&cfg->w);+set_abs(input_dev,ABS_MT_TOUCH_MINOR,&cfg->w);/* finger approach area */-input_set_abs_params(input_dev,ABS_MT_WIDTH_MAJOR,-cfg->w.devmin,cfg->w.devmax,0,0);-input_set_abs_params(input_dev,ABS_MT_WIDTH_MINOR,-cfg->w.devmin,cfg->w.devmax,0,0);+set_abs(input_dev,ABS_MT_WIDTH_MAJOR,&cfg->w);+set_abs(input_dev,ABS_MT_WIDTH_MINOR,&cfg->w);/* finger orientation */-input_set_abs_params(input_dev,ABS_MT_ORIENTATION,--MAX_FINGER_ORIENTATION,-MAX_FINGER_ORIENTATION,0,0);+set_abs(input_dev,ABS_MT_ORIENTATION,&cfg->o);/* finger position */-input_set_abs_params(input_dev,ABS_MT_POSITION_X,-cfg->x.devmin,cfg->x.devmax,0,0);-input_set_abs_params(input_dev,ABS_MT_POSITION_Y,-cfg->y.devmin,cfg->y.devmax,0,0);+set_abs(input_dev,ABS_MT_POSITION_X,&cfg->x);+set_abs(input_dev,ABS_MT_POSITION_Y,&cfg->y);__set_bit(EV_KEY,input_dev->evbit);__set_bit(BTN_TOUCH,input_dev->keybit);
@@ -499,8 +471,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)conststructtp_finger*f;structinput_dev*input=dev->input;intraw_p,raw_x,raw_y,raw_n,i;-intptest,origin,ibt=0,nmin=0,nmax=0;-intabs_x=0,abs_y=0;+intabs_x=0,abs_y=0,n=0;if(size<c->tp_offset||(size-c->tp_offset)%SIZEOF_FINGER!=0)return-EIO;
@@ -525,48 +496,34 @@ static int report_tp_state(struct bcm5974 *dev, int size)"raw: p: %+05d x: %+05d y: %+05d n: %d\n",raw_p,raw_x,raw_y,raw_n);-ptest=int2bound(&c->p,raw_p);-origin=raw2int(f->origin);-/* while tracking finger still valid, count all fingers */-if(ptest>PRESSURE_LOW&&origin){-abs_x=int2bound(&c->x,raw_x-c->x.devmin);-abs_y=int2bound(&c->y,c->y.devmax-raw_y);+if(raw_p>0&&raw2int(f->origin)){+abs_x=raw_x;+abs_y=c->y.min+c->y.max-raw_y;while(raw_n--){-ptest=int2bound(&c->p,-raw2int(f->touch_major));-if(ptest>PRESSURE_LOW)-nmax++;-if(ptest>PRESSURE_HIGH)-nmin++;+if(raw2int(f->touch_major)>0)+n++;f++;}}}-/* set the integrated button if applicable */-if(c->tp_type==TYPE2)-ibt=raw2int(dev->tp_data[BUTTON_TYPE2]);--if(dev->fingers<nmin)-dev->fingers=nmin;-if(dev->fingers>nmax)-dev->fingers=nmax;+input_report_key(input,BTN_TOUCH,n>0);+input_report_key(input,BTN_TOOL_FINGER,n==1);+input_report_key(input,BTN_TOOL_DOUBLETAP,n==2);+input_report_key(input,BTN_TOOL_TRIPLETAP,n==3);+input_report_key(input,BTN_TOOL_QUADTAP,n>3);-input_report_key(input,BTN_TOUCH,dev->fingers>0);-input_report_key(input,BTN_TOOL_FINGER,dev->fingers==1);-input_report_key(input,BTN_TOOL_DOUBLETAP,dev->fingers==2);-input_report_key(input,BTN_TOOL_TRIPLETAP,dev->fingers==3);-input_report_key(input,BTN_TOOL_QUADTAP,dev->fingers>3);--if(dev->fingers>0){+if(n>0){input_report_abs(input,ABS_X,abs_x);input_report_abs(input,ABS_Y,abs_y);}/* type 2 reports button events via ibt only */-if(c->tp_type==TYPE2)+if(c->tp_type==TYPE2){+intibt=raw2int(dev->tp_data[BUTTON_TYPE2]);input_report_key(input,BTN_LEFT,ibt);+}input_sync(input);
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:57
Use of the in-kernel tracking code to convert the driver to MT-B.
With ten fingers on the pad, the in-kernel tracking adds approximately
25 us to the maximum irqsoff latency. Under normal workloads, however,
the tracking has no measurable effect.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/mouse/bcm5974.c | 80 +++++++++++++++----------------------------
1 file changed, 27 insertions(+), 53 deletions(-)
@@ -234,6 +235,9 @@ struct bcm5974 {structbt_data*bt_data;/* button transferred data */structurb*tp_urb;/* trackpad usb request block */u8*tp_data;/* trackpad transferred data */+conststructtp_finger*index[MAX_FINGERS];/* finger index data */+structinput_mt_pospos[MAX_FINGERS];/* position array */+intslots[MAX_FINGERS];/* slot assignments */};/* logical signal quality */
@@ -415,16 +415,13 @@ static void setup_events_to_report(struct input_dev *input_dev,set_abs(input_dev,ABS_MT_POSITION_Y,&cfg->y);__set_bit(EV_KEY,input_dev->evbit);-__set_bit(BTN_TOUCH,input_dev->keybit);-__set_bit(BTN_TOOL_FINGER,input_dev->keybit);-__set_bit(BTN_TOOL_DOUBLETAP,input_dev->keybit);-__set_bit(BTN_TOOL_TRIPLETAP,input_dev->keybit);-__set_bit(BTN_TOOL_QUADTAP,input_dev->keybit);__set_bit(BTN_LEFT,input_dev->keybit);-__set_bit(INPUT_PROP_POINTER,input_dev->propbit);if(cfg->caps&HAS_INTEGRATED_BUTTON)__set_bit(INPUT_PROP_BUTTONPAD,input_dev->propbit);++input_mt_init_slots(input_dev,MAX_FINGERS,+INPUT_MT_POINTER|INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);}/* report button data as logical button state */
@@ -444,10 +441,13 @@ static int report_bt_state(struct bcm5974 *dev, int size)return0;}-staticvoidreport_finger_data(structinput_dev*input,-conststructbcm5974_config*cfg,+staticvoidreport_finger_data(structinput_dev*input,intslot,+conststructinput_mt_pos*pos,conststructtp_finger*f){+input_mt_slot(input,slot);+input_mt_report_slot_state(input,MT_TOOL_FINGER,true);+input_report_abs(input,ABS_MT_TOUCH_MAJOR,raw2int(f->touch_major)<<1);input_report_abs(input,ABS_MT_TOUCH_MINOR,
@@ -458,10 +458,8 @@ static void report_finger_data(struct input_dev *input,raw2int(f->tool_minor)<<1);input_report_abs(input,ABS_MT_ORIENTATION,MAX_FINGER_ORIENTATION-raw2int(f->orientation));-input_report_abs(input,ABS_MT_POSITION_X,raw2int(f->abs_x));-input_report_abs(input,ABS_MT_POSITION_Y,-cfg->y.min+cfg->y.max-raw2int(f->abs_y));-input_mt_sync(input);+input_report_abs(input,ABS_MT_POSITION_X,pos->x);+input_report_abs(input,ABS_MT_POSITION_Y,pos->y);}/* report trackpad data as logical trackpad state */
@@ -470,8 +468,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)conststructbcm5974_config*c=&dev->cfg;conststructtp_finger*f;structinput_dev*input=dev->input;-intraw_p,raw_x,raw_y,raw_n,i;-intabs_x=0,abs_y=0,n=0;+intraw_n,i,n=0;if(size<c->tp_offset||(size-c->tp_offset)%SIZEOF_FINGER!=0)return-EIO;
@@ -480,44 +477,21 @@ static int report_tp_state(struct bcm5974 *dev, int size)f=(conststructtp_finger*)(dev->tp_data+c->tp_offset);raw_n=(size-c->tp_offset)/SIZEOF_FINGER;-/* always track the first finger; when detached, start over */-if(raw_n){--/* report raw trackpad data */-for(i=0;i<raw_n;i++)-report_finger_data(input,c,&f[i]);--raw_p=raw2int(f->touch_major);-raw_x=raw2int(f->abs_x);-raw_y=raw2int(f->abs_y);--dprintk(9,-"bcm5974: "-"raw: p: %+05d x: %+05d y: %+05d n: %d\n",-raw_p,raw_x,raw_y,raw_n);--/* while tracking finger still valid, count all fingers */-if(raw_p>0&&raw2int(f->origin)){-abs_x=raw_x;-abs_y=c->y.min+c->y.max-raw_y;-while(raw_n--){-if(raw2int(f->touch_major)>0)-n++;-f++;-}-}+for(i=0;i<raw_n;i++){+if(raw2int(f[i].touch_major)==0)+continue;+dev->pos[n].x=raw2int(f[i].abs_x);+dev->pos[n].y=c->y.min+c->y.max-raw2int(f[i].abs_y);+dev->index[n++]=&f[i];}-input_report_key(input,BTN_TOUCH,n>0);-input_report_key(input,BTN_TOOL_FINGER,n==1);-input_report_key(input,BTN_TOOL_DOUBLETAP,n==2);-input_report_key(input,BTN_TOOL_TRIPLETAP,n==3);-input_report_key(input,BTN_TOOL_QUADTAP,n>3);+input_mt_assign_slots(input,dev->slots,dev->pos,n);-if(n>0){-input_report_abs(input,ABS_X,abs_x);-input_report_abs(input,ABS_Y,abs_y);-}+for(i=0;i<n;i++)+report_finger_data(input,dev->slots[i],+&dev->pos[i],dev->index[i]);++input_mt_sync_frame(input);/* type 2 reports button events via ibt only */if(c->tp_type==TYPE2){
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:40:59
A null test was left behind during the autoloading work;
the test was introduced by 8d179a9e, but was never completely
reverted.
Reported-by: Dan Carpenter <redacted>
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-multitouch.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:41:00
Going through the motions of printing the debug message information
takes a long time; using the keyboard can lead to a 160 us irqsoff
latency. This patch skips hid_dump_input() when there are no open
handles, which brings latency down to 100 us.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:41:03
A hid device may create several input devices, and a driver may need
to prepare or finalize the configuration per input device. Currently,
there is no sane way for a driver to know when a device has been
configured. This patch adds a callback providing that information.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-input.c | 11 +++++++++--
include/linux/hid.h | 3 +++
2 files changed, 12 insertions(+), 2 deletions(-)
From: Henrik Rydberg <hidden> Date: 2012-08-12 21:44:30
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
Cc: Benjamin Tissoires <redacted>
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-multitouch.c | 162 ++++++++++++++++++-------------------------
1 file changed, 66 insertions(+), 96 deletions(-)
@@ -52,13 +52,6 @@ MODULE_LICENSE("GPL");#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)-structmt_slot{-__s32x,y,p,w,h;-__s32contactid;/* the device ContactID assigned to this slot */-booltouch_state;/* is the touch valid? */-boolseen_in_this_frame;/* has this slot been updated */-};-structmt_class{__s32name;/* MT_CLS */__s32quirks;
@@ -76,7 +69,6 @@ struct mt_fields {};structmt_device{-structmt_slotcurdata;/* placeholder of incoming data */structmt_classmtclass;/* our mt device class */structmt_fields*fields;/* temporary placeholder for storing themultitouchfields*/
@@ -93,7 +85,9 @@ struct mt_device {*1meansweshoulduseaserialprotocol*>1meanshybrid(multitouch)protocol*/boolcurvalid;/* is the current contact valid? */-structmt_slot*slots;+__s32x,y,p,w,h;+__s32contactid;/* the device ContactID assigned to this slot */+booltouch_state;/* is the touch valid? */};/* classes of device behavior */
@@ -128,31 +122,12 @@ struct mt_device {staticintcypress_compute_slot(structmt_device*td){-if(td->curdata.contactid!=0||td->num_received==0)-returntd->curdata.contactid;+if(td->contactid!=0||td->num_received==0)+returntd->contactid;elsereturn-1;}-staticintfind_slot_from_contactid(structmt_device*td)-{-inti;-for(i=0;i<td->maxcontacts;++i){-if(td->slots[i].contactid==td->curdata.contactid&&-td->slots[i].touch_state)-returni;-}-for(i=0;i<td->maxcontacts;++i){-if(!td->slots[i].seen_in_this_frame&&-!td->slots[i].touch_state)-returni;-}-/* should not occurs. If this happens that means-*thatthedevicesentmoretouchesthatitsays-*inthereportdescriptor.Itisignoredthen.*/-return-1;-}-staticstructmt_classmt_classes[]={{.name=MT_CLS_DEFAULT,.quirks=MT_QUIRK_NOT_SEEN_MEANS_UP},
@@ -478,25 +471,43 @@ static int mt_compute_slot(struct mt_device *td)returntd->num_received;if(quirks&MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)-returntd->curdata.contactid-1;+returntd->contactid-1;-returnfind_slot_from_contactid(td);+returninput_mt_assign_slot_by_id(input,td->contactid);}/**thisfunctioniscalledwhenawholecontacthasbeenprocessed,*sothatitcanassignittoaslotandstorethedatathere*/-staticvoidmt_complete_slot(structmt_device*td)+staticvoidmt_complete_slot(structmt_device*td,structinput_dev*input){-td->curdata.seen_in_this_frame=true;-if(td->curvalid){-intslotnum=mt_compute_slot(td);+intslot;-if(slotnum>=0&&slotnum<td->maxcontacts)-td->slots[slotnum]=td->curdata;-}td->num_received++;+if(!td->curvalid)+return;++slot=mt_compute_slot(td,input);+if(slot<0||slot>=td->maxcontacts)+return;++input_mt_slot(input,slot);+input_mt_report_slot_state(input,MT_TOOL_FINGER,td->touch_state);+if(td->touch_state){+/* this finger is on the screen */+intwide=(td->w>td->h);+/* divided by two to match visual scale of touch */+intmajor=max(td->w,td->h)>>1;+intminor=min(td->w,td->h)>>1;++input_event(input,EV_ABS,ABS_MT_POSITION_X,td->x);+input_event(input,EV_ABS,ABS_MT_POSITION_Y,td->y);+input_event(input,EV_ABS,ABS_MT_ORIENTATION,wide);+input_event(input,EV_ABS,ABS_MT_PRESSURE,td->p);+input_event(input,EV_ABS,ABS_MT_TOUCH_MAJOR,major);+input_event(input,EV_ABS,ABS_MT_TOUCH_MINOR,minor);+}}
@@ -504,52 +515,20 @@ static void mt_complete_slot(struct mt_device *td)*thisfunctioniscalledwhenawholepackethasbeenreceivedandprocessed,*sothatitcandecidewhattosendtotheinputlayer.*/-staticvoidmt_emit_event(structmt_device*td,structinput_dev*input)+staticvoidmt_sync_frame(structmt_device*td,structinput_dev*input){-inti;--for(i=0;i<td->maxcontacts;++i){-structmt_slot*s=&(td->slots[i]);-if((td->mtclass.quirks&MT_QUIRK_NOT_SEEN_MEANS_UP)&&-!s->seen_in_this_frame){-s->touch_state=false;-}--input_mt_slot(input,i);-input_mt_report_slot_state(input,MT_TOOL_FINGER,-s->touch_state);-if(s->touch_state){-/* this finger is on the screen */-intwide=(s->w>s->h);-/* divided by two to match visual scale of touch */-intmajor=max(s->w,s->h)>>1;-intminor=min(s->w,s->h)>>1;--input_event(input,EV_ABS,ABS_MT_POSITION_X,s->x);-input_event(input,EV_ABS,ABS_MT_POSITION_Y,s->y);-input_event(input,EV_ABS,ABS_MT_ORIENTATION,wide);-input_event(input,EV_ABS,ABS_MT_PRESSURE,s->p);-input_event(input,EV_ABS,ABS_MT_TOUCH_MAJOR,major);-input_event(input,EV_ABS,ABS_MT_TOUCH_MINOR,minor);-}-s->seen_in_this_frame=false;--}--input_mt_report_pointer_emulation(input,true);+input_mt_sync_frame(input);input_sync(input);td->num_received=0;}--staticintmt_event(structhid_device*hid,structhid_field*field,structhid_usage*usage,__s32value){structmt_device*td=hid_get_drvdata(hid);__s32quirks=td->mtclass.quirks;-if(hid->claimed&HID_CLAIMED_INPUT&&td->slots){+if(hid->claimed&HID_CLAIMED_INPUT){switch(usage->hid){caseHID_DG_INRANGE:if(quirks&MT_QUIRK_ALWAYS_VALID)
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted hunk
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
@@ -1777,6 +1777,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)if(test_bit(i,dev->relbit))events++;+/* Make room for KEY and MSC events */+events+=7;
Hi Henrik,
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Ping
quoted hunk
+
return events;
}
@@ -1815,6 +1818,7 @@ int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); struct input_handler *handler;+ unsigned int packet_size; const char *path; int error;
@@ -1827,9 +1831,9 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev);- if (!dev->hint_events_per_packet)- dev->hint_events_per_packet =- input_estimate_events_per_packet(dev);+ packet_size = input_estimate_events_per_packet(dev);+ if (dev->hint_events_per_packet < packet_size)+ dev->hint_events_per_packet = packet_size; /* * If delay and period are pre-set by the driver, then autorepeating--
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday, August 14, 2012 12:32:21 PM Ping Cheng wrote:
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
input_estimate_events_per_packet(struct input_dev *dev)>
if (test_bit(i, dev->relbit))
events++;
+ /* Make room for KEY and MSC events */
+ events += 7;
Hi Henrik,
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Because that would result in gross over-estimation for many devices -
my keyboard has 100+ keys but it never sends all of them in one event
frame, not even if I can get a cat to lay on it ;)
--
Dmitry
From: Henrik Rydberg <hidden> Date: 2012-08-14 19:58:01
Hi Ping,
Long time no see. :-)
quoted
+ /* Make room for KEY and MSC events */
+ events += 7;
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Keyboards register a large amount of different keys, but seldom send
more than one or two at a time. The value 7 is ad hoc, admittedly, but
it makes the default buffer 8 bytes, which happens to precisely match
the default buffer in evdev.
Thanks,
Henrik
On Tue, Aug 14, 2012 at 12:53 PM, Dmitry Torokhov
[off-list ref] wrote:
On Tuesday, August 14, 2012 12:32:21 PM Ping Cheng wrote:
quoted
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
input_estimate_events_per_packet(struct input_dev *dev)>
if (test_bit(i, dev->relbit))
events++;
+ /* Make room for KEY and MSC events */
+ events += 7;
Hi Henrik,
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Because that would result in gross over-estimation for many devices -
my keyboard has 100+ keys but it never sends all of them in one event
frame, not even if I can get a cat to lay on it ;)
Thanks for the prompt reply. I thought you were on vacation ;-).
So, what device are we talking about here? I thought it is a touch
device with a few extra buttons, which are reported as key events. Am
I missing something?
If it is a touch device, we won't have too many buttons. So,
test_bit(i, dev->keybit) won't be true for more than the number of
buttons that declared by __set_bit().
I would think we could play a keyboard (this keyboard does not have
letters on it ;-) with ten fingers.
Ping
On Tue, Aug 14, 2012 at 1:01 PM, Henrik Rydberg [off-list ref] wrote:
Hi Ping,
Long time no see. :-)
quoted
quoted
+ /* Make room for KEY and MSC events */
+ events += 7;
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Keyboards register a large amount of different keys, but seldom send
more than one or two at a time. The value 7 is ad hoc, admittedly, but
it makes the default buffer 8 bytes, which happens to precisely match
the default buffer in evdev.
That can be a valid reason until we need to report more keys
simultaneously. Please update the comments so we know why we end up
with 7.
Thank you.
Ping
On Tue, Aug 14, 2012 at 01:50:38PM -0700, Ping Cheng wrote:
On Tue, Aug 14, 2012 at 12:53 PM, Dmitry Torokhov
[off-list ref] wrote:
quoted
On Tuesday, August 14, 2012 12:32:21 PM Ping Cheng wrote:
quoted
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/input.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
input_estimate_events_per_packet(struct input_dev *dev)>
if (test_bit(i, dev->relbit))
events++;
+ /* Make room for KEY and MSC events */
+ events += 7;
Hi Henrik,
It is nice to get rid of the redundant pieces and to incorporate
common functions. Thank you.
I have a question about the code above though. Why do we use 7
instead of going through the keys like:
for (i = 0; i < KEY_MAX; i++)
if (test_bit(i, dev->keybit))
events++;
Because that would result in gross over-estimation for many devices -
my keyboard has 100+ keys but it never sends all of them in one event
frame, not even if I can get a cat to lay on it ;)
Thanks for the prompt reply. I thought you were on vacation ;-).
No, just generally busy ;(
So, what device are we talking about here? I thought it is a touch
device with a few extra buttons, which are reported as key events. Am
I missing something?
I was talking about a bog-standard computer keyboard here.
If it is a touch device, we won't have too many buttons. So,
test_bit(i, dev->keybit) won't be true for more than the number of
buttons that declared by __set_bit().
input_estimate_events_per_packet() is a generic routine that is used for
all devices, not only [multi]touch.
I would think we could play a keyboard (this keyboard does not have
letters on it ;-) with ten fingers.
But even that keyboard would have more than 10 keys, right? So even
though max_events should be 10 + 10 + 1 (10 keys, 10 msc, syn) your loop
would produce what 88 + 88 + 1 for full size music keyboard?
Thanks.
--
Dmitry
On Tue, Aug 14, 2012 at 2:12 PM, Dmitry Torokhov
[off-list ref] wrote:
quoted
quoted
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Many MT devices send a number of keys along with the mt information.
This patch makes sure that there is room for them in the packet
buffer.
So, what device are we talking about here? I thought it is a touch
device with a few extra buttons, which are reported as key events. Am
I missing something?
I was talking about a bog-standard computer keyboard here.
quoted
If it is a touch device, we won't have too many buttons. So,
test_bit(i, dev->keybit) won't be true for more than the number of
buttons that declared by __set_bit().
input_estimate_events_per_packet() is a generic routine that is used for
all devices, not only [multi]touch.
I understand you are talking about standard keyboard. And I know this
routine is for all devices.
However, from the commit comments, the patch is to address an MT
issue. If it is not just for MT, we need either to make it clear in
the comments or to verify the type of the device in the code.
quoted
I would think we could play a keyboard (this keyboard does not have
letters on it ;-) with ten fingers.
But even that keyboard would have more than 10 keys, right? So even
though max_events should be 10 + 10 + 1 (10 keys, 10 msc, syn) your loop
would produce what 88 + 88 + 1 for full size music keyboard?
No, I was not talking about implementing full music keyboard functions
in the kernel. My point was: why do we take 7 instead of 10, or
another number?
In fact, 7 works for me as long as we explain the rationale behind the
decision. I do not have a device that needs to post 10 button events
simultaneously, yet ;-).
Ping
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
Signed-off-by: Henrik Rydberg <redacted>
I went through the patchset except those for bcm5974. Since there are
changes that affect other drivers, do you plan to update the affected
drivers as well?
I have a minor question below inline. You can add my Reviewed-by tag
after updating commit comments for 02/19.
Thank you for your effort.
Ping
@@ -45,6 +53,28 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,input_set_abs_params(dev,ABS_MT_SLOT,0,num_slots-1,0,0);input_set_abs_params(dev,ABS_MT_TRACKING_ID,0,TRKID_MAX,0,0);+if(flags&(INPUT_MT_POINTER|INPUT_MT_DIRECT)){+__set_bit(EV_KEY,dev->evbit);+__set_bit(BTN_TOUCH,dev->keybit);++copy_abs(dev,ABS_X,ABS_MT_POSITION_X);+copy_abs(dev,ABS_Y,ABS_MT_POSITION_Y);+copy_abs(dev,ABS_PRESSURE,ABS_MT_PRESSURE);+}+if(flags&INPUT_MT_POINTER){+__set_bit(BTN_TOOL_FINGER,dev->keybit);+__set_bit(BTN_TOOL_DOUBLETAP,dev->keybit);+if(num_slots>=3)+__set_bit(BTN_TOOL_TRIPLETAP,dev->keybit);+if(num_slots>=4)+__set_bit(BTN_TOOL_QUADTAP,dev->keybit);+if(num_slots>=5)+__set_bit(BTN_TOOL_QUINTTAP,dev->keybit);+__set_bit(INPUT_PROP_POINTER,dev->propbit);+}+if(flags&INPUT_MT_DIRECT)+__set_bit(INPUT_PROP_DIRECT,dev->propbit);+/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)input_mt_set_value(&mt->slots[i],ABS_MT_TRACKING_ID,-1);
@@ -15,12 +15,17 @@#define TRKID_MAX 0xffff+#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */+#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */+#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame *//***structinput_mt_slot-representsthestateofaninputMTslot*@abs:holdscurrentvaluesofABS_MTaxesforthisslot+*@frame:lastframeatwhichinput_mt_report_slot_state()wascalled*/structinput_mt_slot{intabs[ABS_MT_LAST-ABS_MT_FIRST+1];+unsignedintframe;};/**
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Henrik Rydberg <hidden> Date: 2012-08-16 18:03:27
On Wed, Aug 15, 2012 at 04:28:17PM -0700, Ping Cheng wrote:
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
Signed-off-by: Henrik Rydberg <redacted>
I went through the patchset except those for bcm5974. Since there are
changes that affect other drivers, do you plan to update the affected
drivers as well?
I am not sure what you mean here? There is a patch with in-kernel api
changes, which also changes all drivers using the api. Some of those
drivers will benefit from further changes, but that is a different
story.
quoted
+void input_mt_sync_frame(struct input_dev *dev)
+{
+ struct input_mt *mt = dev->mt;
+ struct input_mt_slot *s;
+
+ if (!mt)
+ return;
+
+ if (mt->flags & INPUT_MT_DROP_UNUSED) {
+ for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+ if (s->frame == mt->frame)
+ continue;
+ input_mt_slot(dev, s - mt->slots);
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ }
+ }
+
+ if (mt->flags & INPUT_MT_POINTER)
+ input_mt_report_pointer_emulation(dev, true);
+
+ if (mt->flags & INPUT_MT_DIRECT)
+ input_mt_report_pointer_emulation(dev, false);
+
+ mt->frame++;
Where do we reset this frame counter?
Why would we reset it? It is used in the core to keep track of changes
per frame, and may wrap around without issues.
Henrik
On Thu, Aug 16, 2012 at 11:07 AM, Henrik Rydberg [off-list ref] wrote:
On Wed, Aug 15, 2012 at 04:28:17PM -0700, Ping Cheng wrote:
quoted
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
Signed-off-by: Henrik Rydberg <redacted>
I went through the patchset except those for bcm5974. Since there are
changes that affect other drivers, do you plan to update the affected
drivers as well?
I am not sure what you mean here? There is a patch with in-kernel api
changes, which also changes all drivers using the api. Some of those
drivers will benefit from further changes, but that is a different
story.
I meant that some new routines require individual MT drivers to be
updated to adapt to the new implementation.
For example, the new input_mt_init_slots() takes care of the
__set_bit() functions in one place. That is great. But, it requires
wacom_wac.c to be updated since it has an interface change. I guess
there are other drivers calling input_mt_init_slots as well.
I was wondering if you plan to update all drivers after this patchset
is accepted or if you need us to chime in.
quoted
quoted
+void input_mt_sync_frame(struct input_dev *dev)
+{
+ struct input_mt *mt = dev->mt;
+ struct input_mt_slot *s;
+
+ if (!mt)
+ return;
+
+ if (mt->flags & INPUT_MT_DROP_UNUSED) {
+ for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+ if (s->frame == mt->frame)
+ continue;
+ input_mt_slot(dev, s - mt->slots);
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ }
+ }
+
+ if (mt->flags & INPUT_MT_POINTER)
+ input_mt_report_pointer_emulation(dev, true);
+
+ if (mt->flags & INPUT_MT_DIRECT)
+ input_mt_report_pointer_emulation(dev, false);
+
+ mt->frame++;
Where do we reset this frame counter?
Why would we reset it? It is used in the core to keep track of changes
per frame, and may wrap around without issues.
From what I see, frame/mt is only initialized when driver starts.
Frame will be increased by MT events while the driver running. If this
is true, won't it be possible the value gets too large?
I might have missed a detail about frame somewhere in the patchset.
Ping
On Thu, Aug 16, 2012 at 11:07 AM, Henrik Rydberg [off-list ref] wrote:
On Wed, Aug 15, 2012 at 04:28:17PM -0700, Ping Cheng wrote:
quoted
On Sun, Aug 12, 2012 at 2:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
Signed-off-by: Henrik Rydberg <redacted>
I went through the patchset except those for bcm5974. Since there are
changes that affect other drivers, do you plan to update the affected
drivers as well?
I am not sure what you mean here? There is a patch with in-kernel api
changes, which also changes all drivers using the api. Some of those
drivers will benefit from further changes, but that is a different
story.
Just to clarify a little bit more. Patch 08/19 was only a generic
update. A complete update should introduce INPUT_MT_POINTER and
INPUT_MT_DIRECT so the drivers can fully utilize the new feature.
Now I understand you expect us to update the "different story".
Thanks.
Ping
Ping
From: Henrik Rydberg <hidden> Date: 2012-08-16 20:01:48
For example, the new input_mt_init_slots() takes care of the
__set_bit() functions in one place. That is great. But, it requires
wacom_wac.c to be updated since it has an interface change. I guess
there are other drivers calling input_mt_init_slots as well.
The default behavior in the "new" input_mt_init_slots(), i.e. with the
zero flags argument added to all the drivers, is exactly the same as
before. No further changes are necessary.
Yes, some drivers could definitely start using some of the flags to
good advantage, but there is no rush to make that happen. Such changes
would of course involve the driver maintainers.
I was wondering if you plan to update all drivers after this patchset
is accepted or if you need us to chime in.
Thank you, the best is definitely if you want to do it yourself. Let's
just see where the latency-related work takes us first, since it might
affect how to send data from drivers.
From what I see, frame/mt is only initialized when driver starts.
Frame will be increased by MT events while the driver running. If this
is true, won't it be possible the value gets too large?
Yes, but as is apparent from the code, the semantics of that variable
is not to count the number of frames since the dawn of times, but to
keep track of changes per frame.
Thanks,
Henrik
From: Benjamin Tissoires <hidden> Date: 2012-08-20 13:36:02
Acked-by: Benjamin Tissoires <redacted>
On Sun, Aug 12, 2012 at 11:42 PM, Henrik Rydberg [off-list ref] wrote:
quoted hunk
A null test was left behind during the autoloading work;
the test was introduced by 8d179a9e, but was never completely
reverted.
Reported-by: Dan Carpenter <redacted>
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-multitouch.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Benjamin Tissoires <hidden> Date: 2012-08-20 13:36:28
Hi Henrik,
thanks for this patch set.
I'm also happy when someone tries to factorize and optimize some code.
I have a few concerns though:
On Sun, Aug 12, 2012 at 11:42 PM, Henrik Rydberg [off-list ref] wrote:
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
I was really wondering why you needed to put in input-mt something
that appeared only in hid-multitouch.... until I noted that you are
going to use it for bcm5974.
Maybe you should add a comment on it (otherwise, it seams like you're
just adding unused code). Maybe this would also help people
understanding the *frame thing.
@@ -45,6 +53,28 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,input_set_abs_params(dev,ABS_MT_SLOT,0,num_slots-1,0,0);input_set_abs_params(dev,ABS_MT_TRACKING_ID,0,TRKID_MAX,0,0);+if(flags&(INPUT_MT_POINTER|INPUT_MT_DIRECT)){+__set_bit(EV_KEY,dev->evbit);+__set_bit(BTN_TOUCH,dev->keybit);++copy_abs(dev,ABS_X,ABS_MT_POSITION_X);+copy_abs(dev,ABS_Y,ABS_MT_POSITION_Y);+copy_abs(dev,ABS_PRESSURE,ABS_MT_PRESSURE);+}+if(flags&INPUT_MT_POINTER){+__set_bit(BTN_TOOL_FINGER,dev->keybit);+__set_bit(BTN_TOOL_DOUBLETAP,dev->keybit);+if(num_slots>=3)+__set_bit(BTN_TOOL_TRIPLETAP,dev->keybit);+if(num_slots>=4)+__set_bit(BTN_TOOL_QUADTAP,dev->keybit);+if(num_slots>=5)+__set_bit(BTN_TOOL_QUINTTAP,dev->keybit);+__set_bit(INPUT_PROP_POINTER,dev->propbit);+}+if(flags&INPUT_MT_DIRECT)+__set_bit(INPUT_PROP_DIRECT,dev->propbit);+/* Mark slots as 'unused' */for(i=0;i<num_slots;i++)input_mt_set_value(&mt->slots[i],ABS_MT_TRACKING_ID,-1);
The function input_mt_report_pointer_emulation could be called twice
if the driver has both INPUT_MT_POINTER and INPUT_MT_DIRECT flags. Are
they mutual exclusive?
Cheers,
Benjamin
@@ -15,12 +15,17 @@#define TRKID_MAX 0xffff+#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */+#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */+#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame *//***structinput_mt_slot-representsthestateofaninputMTslot*@abs:holdscurrentvaluesofABS_MTaxesforthisslot+*@frame:lastframeatwhichinput_mt_report_slot_state()wascalled*/structinput_mt_slot{intabs[ABS_MT_LAST-ABS_MT_FIRST+1];+unsignedintframe;};/**
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Benjamin Tissoires <hidden> Date: 2012-08-20 13:36:39
Hello Henrik,
On Sun, Aug 12, 2012 at 11:42 PM, Henrik Rydberg [off-list ref] wrote:
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
This patch seems to be a little bit complex.
It has very good things, but also many things that hinders the readability.
And you should also remove the /* touchscreen emulation */ things in
mt_input_mapping as input_mt_init_slots handles now the init of ABS_X
ABS_Y and ABS_PRESSURE.
quoted hunk
Cc: Benjamin Tissoires <redacted>
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/hid/hid-multitouch.c | 162 ++++++++++++++++++-------------------------
1 file changed, 66 insertions(+), 96 deletions(-)
@@ -52,13 +52,6 @@ MODULE_LICENSE("GPL");#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)-structmt_slot{-__s32x,y,p,w,h;-__s32contactid;/* the device ContactID assigned to this slot */-booltouch_state;/* is the touch valid? */-boolseen_in_this_frame;/* has this slot been updated */-};
Why removing this struct?
Removing it infers a lot of unneeded changes in the patch.
As the mt_sync_frame handle the quirk NOT_SEEN_MEANS_UP, we should
just remove the field seen_in_this_frame.
@@ -76,7 +69,6 @@ struct mt_fields { }; struct mt_device {- struct mt_slot curdata; /* placeholder of incoming data */ struct mt_class mtclass; /* our mt device class */ struct mt_fields *fields; /* temporary placeholder for storing the multitouch fields */
@@ -93,7 +85,9 @@ struct mt_device { * 1 means we should use a serial protocol * > 1 means hybrid (multitouch) protocol */ bool curvalid; /* is the current contact valid? */- struct mt_slot *slots;+ __s32 x, y, p, w, h;+ __s32 contactid; /* the device ContactID assigned to this slot */+ bool touch_state; /* is the touch valid? */
Again, by keeping the first field, you don't lose any memory and
things are packed and organized!
(having x, y, etc... at the root of the device struct is kind of weird...)
This patch contains many unneeded modifications of this type.... :-(
else
return -1;
}
-static int find_slot_from_contactid(struct mt_device *td)
-{
- int i;
- for (i = 0; i < td->maxcontacts; ++i) {
- if (td->slots[i].contactid == td->curdata.contactid &&
- td->slots[i].touch_state)
- return i;
- }
- for (i = 0; i < td->maxcontacts; ++i) {
- if (!td->slots[i].seen_in_this_frame &&
- !td->slots[i].touch_state)
- return i;
- }
- /* should not occurs. If this happens that means
- * that the device sent more touches that it says
- * in the report descriptor. It is ignored then. */
- return -1;
-}
-
These two tests are really strange: the function input_mt_init_slots
already sets those bits....
Maybe we should handle INPUT_PROP_POINTER, INPUT_PROP_DIRECT by
keeping the flag instead of setting the bits and re-read them to
finally re-set them...
And yes, I know that input_mt_init_slots does a lot more than just
setting those two bits, but it's the impression I feel when reading
this.
Anyway, besides this things, I'm happy with the input_configured callback.
@@ -478,25 +471,43 @@ static int mt_compute_slot(struct mt_device *td) return td->num_received; if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)- return td->curdata.contactid - 1;+ return td->contactid - 1;- return find_slot_from_contactid(td);+ return input_mt_assign_slot_by_id(input, td->contactid); } /* * this function is called when a whole contact has been processed, * so that it can assign it to a slot and store the data there */-static void mt_complete_slot(struct mt_device *td)+static void mt_complete_slot(struct mt_device *td, struct input_dev *input) {- td->curdata.seen_in_this_frame = true;- if (td->curvalid) {- int slotnum = mt_compute_slot(td);+ int slot;- if (slotnum >= 0 && slotnum < td->maxcontacts)- td->slots[slotnum] = td->curdata;- } td->num_received++;+ if (!td->curvalid)+ return;++ slot = mt_compute_slot(td, input);+ if (slot < 0 || slot >= td->maxcontacts)+ return;++ input_mt_slot(input, slot);+ input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch_state);+ if (td->touch_state) {+ /* this finger is on the screen */+ int wide = (td->w > td->h);+ /* divided by two to match visual scale of touch */+ int major = max(td->w, td->h) >> 1;+ int minor = min(td->w, td->h) >> 1;++ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);+ input_event(input, EV_ABS, ABS_MT_PRESSURE, td->p);+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);+ } }
@@ -504,52 +515,20 @@ static void mt_complete_slot(struct mt_device *td) * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */-static void mt_emit_event(struct mt_device *td, struct input_dev *input)+static void mt_sync_frame(struct mt_device *td, struct input_dev *input) {- int i;-- for (i = 0; i < td->maxcontacts; ++i) {- struct mt_slot *s = &(td->slots[i]);- if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&- !s->seen_in_this_frame) {- s->touch_state = false;- }-- input_mt_slot(input, i);- input_mt_report_slot_state(input, MT_TOOL_FINGER,- s->touch_state);- if (s->touch_state) {- /* this finger is on the screen */- int wide = (s->w > s->h);- /* divided by two to match visual scale of touch */- int major = max(s->w, s->h) >> 1;- int minor = min(s->w, s->h) >> 1;-- input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);- input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);- input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);- input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);- }- s->seen_in_this_frame = false;-- }-- input_mt_report_pointer_emulation(input, true);+ input_mt_sync_frame(input); input_sync(input); td->num_received = 0; }-- static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass.quirks;- if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {+ if (hid->claimed & HID_CLAIMED_INPUT) {
the "td->slots" test was ugly ;-)
Thanks,
Benjamin
quoted hunk
switch (usage->hid) {
case HID_DG_INRANGE:
if (quirks & MT_QUIRK_ALWAYS_VALID)
@@ -560,29 +539,29 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, case HID_DG_TIPSWITCH: if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) td->curvalid = value;- td->curdata.touch_state = value;+ td->touch_state = value; break; case HID_DG_CONFIDENCE: if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) td->curvalid = value; break; case HID_DG_CONTACTID:- td->curdata.contactid = value;+ td->contactid = value; break; case HID_DG_TIPPRESSURE:- td->curdata.p = value;+ td->p = value; break; case HID_GD_X:- td->curdata.x = value;+ td->x = value; break; case HID_GD_Y:- td->curdata.y = value;+ td->y = value; break; case HID_DG_WIDTH:- td->curdata.w = value;+ td->w = value; break; case HID_DG_HEIGHT:- td->curdata.h = value;+ td->h = value; break; case HID_DG_CONTACTCOUNT: /*
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Henrik Rydberg <hidden> Date: 2012-08-20 15:57:14
quoted
Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops
unseen contacts and performs pointer emulation.
I was really wondering why you needed to put in input-mt something
that appeared only in hid-multitouch.... until I noted that you are
going to use it for bcm5974.
True, you were only copied in on the patch specific to
hid-multitouch. The core changes will naturally be used for some other
drivers as well.
Maybe you should add a comment on it (otherwise, it seams like you're
just adding unused code). Maybe this would also help people
understanding the *frame thing.
More comments on those plans, agreed. The "frame thing" is really only
an input core change; it can most likely be better explained as well,
but it really should not matter to drivers.
quoted
+void input_mt_sync_frame(struct input_dev *dev)
+{
+ struct input_mt *mt = dev->mt;
+ struct input_mt_slot *s;
+
+ if (!mt)
+ return;
+
+ if (mt->flags & INPUT_MT_DROP_UNUSED) {
+ for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+ if (s->frame == mt->frame)
+ continue;
+ input_mt_slot(dev, s - mt->slots);
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
Shouldn't we rely on input_mt_report_slot_state instead of doing it by hand?
No, input_mt_report_slot_state() is a driver api function with side
effects which are not desired here.
The function input_mt_report_pointer_emulation could be called twice
if the driver has both INPUT_MT_POINTER and INPUT_MT_DIRECT flags. Are
they mutual exclusive?
You are right, and they are not. Will fix.
Thanks,
Henrik
From: Henrik Rydberg <hidden> Date: 2012-08-20 15:57:18
Hi Benjamin,
This patch seems to be a little bit complex.
It has very good things, but also many things that hinders the readability.
And you should also remove the /* touchscreen emulation */ things in
mt_input_mapping as input_mt_init_slots handles now the init of ABS_X
ABS_Y and ABS_PRESSURE.
Yes, it could be changed as well, like the bit patterns. As you
mention below, the logic around the bits could be enhanced, and the
ABS_X/Y should go in that set of changes.
quoted
-struct mt_slot {
- __s32 x, y, p, w, h;
- __s32 contactid; /* the device ContactID assigned to this slot */
- bool touch_state; /* is the touch valid? */
- bool seen_in_this_frame;/* has this slot been updated */
-};
Why removing this struct?
Removing it infers a lot of unneeded changes in the patch.
As the mt_sync_frame handle the quirk NOT_SEEN_MEANS_UP, we should
just remove the field seen_in_this_frame.
Well, it is no longer needed, but sure, one could keep it and just
remove the unused fields.
These two tests are really strange: the function input_mt_init_slots
already sets those bits....
Maybe we should handle INPUT_PROP_POINTER, INPUT_PROP_DIRECT by
keeping the flag instead of setting the bits and re-read them to
finally re-set them...
Ok, I will extend the patchset for hid-multitouch to include such
changes as well.
Thanks,
Henrik
From: Henrik Rydberg <hidden> Date: 2012-08-22 20:53:47
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
Signed-off-by: Henrik Rydberg <redacted>
---
Hi Benjamin,
Maybe this patch works better? It has received limited testing so far.
Henrik
drivers/hid/hid-multitouch.c | 133 +++++++++++++++----------------------------
1 file changed, 46 insertions(+), 87 deletions(-)
@@ -56,7 +56,6 @@ struct mt_slot {__s32x,y,p,w,h;__s32contactid;/* the device ContactID assigned to this slot */booltouch_state;/* is the touch valid? */-boolseen_in_this_frame;/* has this slot been updated */};structmt_class{
@@ -93,7 +92,7 @@ struct mt_device {*1meansweshoulduseaserialprotocol*>1meanshybrid(multitouch)protocol*/boolcurvalid;/* is the current contact valid? */-structmt_slot*slots;+unsignedmt_flags;/* flags to pass to input-mt */};/* classes of device behavior */
@@ -134,25 +133,6 @@ static int cypress_compute_slot(struct mt_device *td)return-1;}-staticintfind_slot_from_contactid(structmt_device*td)-{-inti;-for(i=0;i<td->maxcontacts;++i){-if(td->slots[i].contactid==td->curdata.contactid&&-td->slots[i].touch_state)-returni;-}-for(i=0;i<td->maxcontacts;++i){-if(!td->slots[i].seen_in_this_frame&&-!td->slots[i].touch_state)-returni;-}-/* should not occurs. If this happens that means-*thatthedevicesentmoretouchesthatitsays-*inthereportdescriptor.Itisignoredthen.*/-return-1;-}-staticstructmt_classmt_classes[]={{.name=MT_CLS_DEFAULT,.quirks=MT_QUIRK_NOT_SEEN_MEANS_UP},
@@ -319,24 +299,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,*Weneedtoignorefieldsthatbelongtoothercollections*suchasMousethatmighthavethesameGenericDesktopusages.*/if(field->application==HID_DG_TOUCHSCREEN)-set_bit(INPUT_PROP_DIRECT,hi->input->propbit);+td->mt_flags|=INPUT_MT_DIRECT;elseif(field->application!=HID_DG_TOUCHPAD)return0;-/* In case of an indirect device (touchpad), we need to add-*specificBTN_TOOL_*tobehandledbythesynapticsxorg-*driver.-*Wealsoconsiderthattouchscreensprovidingbuttonsaretouchpads.+/*+*Modeltouchscreensprovidingbuttonsastouchpads.*/if(field->application==HID_DG_TOUCHPAD||-(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON||-cls->is_indirect){-set_bit(INPUT_PROP_POINTER,hi->input->propbit);-set_bit(BTN_TOOL_FINGER,hi->input->keybit);-set_bit(BTN_TOOL_DOUBLETAP,hi->input->keybit);-set_bit(BTN_TOOL_TRIPLETAP,hi->input->keybit);-set_bit(BTN_TOOL_QUADTAP,hi->input->keybit);-}+(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON)+td->mt_flags|=INPUT_MT_POINTER;/* eGalax devices provide a Digitizer.Stylus input which overrides*thecorrectDigitizers.FingerX/Yranges.
From: Daniel Kurtz <hidden> Date: 2012-08-24 04:03:27
On Mon, Aug 13, 2012 at 5:42 AM, Henrik Rydberg [off-list ref] wrote:
On heavy event loads, such as a multitouch driver, the irqsoff latency
can be as high as 250 us. By accumulating a frame worth of data
before passing it on, the latency can be dramatically reduced. As a
side effect, the special EV_SYN handling can be removed, since the
frame is now atomic.
This patch(set) is very interesting and exciting. Thanks!
Some questions and comments inline...
This patch adds the events() handler callback and uses it if it
exists. The latency is improved by 50 us even without the callback.
How much of the savings is just from reducing the number of
add_input_randomness() calls from 1-per-input_value to 1-per-frame?
Could you achieve similar savings by only calling add_input_randomness
on the first input_value after each EV_SYN/SYN_REPORT (ie "when sync =
true")?
The only thing that is a little strange with this function is that it
actually changes the 'vals' array due to in-place filtering. It means
that input_to_handler can't handle const arrays of vals, which may
have a performance impact in some cases (like key repeat). You are
relying on this behavior since you want to pass the final filtered
input_value array to ->events() without copying, but this seems to be
optimizing the 'filtered' case relative to the (normal?) unfiltered
behavior. Probably not worth changing, though.
if (handler->filter == false), you could skip the whole loop and just
assign end = vals + count.
Also, the original version assumed that if a handler had the grab, it
couldn't be a filter, and would skip filtering entirely.
Maybe we can have a handler->filter_events(handle, vals, count) that
returns the number of events left after filtering.
This would allow more sophisticated filtering that could inspect an
entire frame.
In the original version, one handler would not call both ->filter()
and ->event().
I'm not sure if that was a bug or a feature. But, you now make it possible.
However, this opens up the possibility of a filter handler processing
events via its ->event that would get filtered out by a later
handler's filter.
In sum, I think if we assume a handler only has either ->filter or
->event (->events), then we can split this function into two, one that
only does filtering on filters, and one that only passes the resulting
filtered events.
quoted hunk
+ if (handler->events)
+ handler->events(handle, vals, count);
+ else
+ for (v = vals; v != end; v++)
+ handler->event(handle, v->type, v->code, v->value);
+
+ return count;
+}
+
+/*
+ * Pass values first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_values(struct input_dev *dev,
+ struct input_value *vals, size_t count)
+{
+ struct input_handle *handle;
+ struct input_value *v;
- handler = handle->handler;
- if (!handler->filter) {
- if (filtered)
- break;
+ if (!count)
+ return;
- handler->event(handle, type, code, value);
+ rcu_read_lock();
- } else if (handler->filter(handle, type, code, value))
- filtered = true;
- }
+ handle = rcu_dereference(dev->grab);
+ if (handle) {
+ count = input_to_handler(handle, vals, count);
+ } else {
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+ if (handle->open)
+ count = input_to_handler(handle, vals, count);
}
rcu_read_unlock();
+ add_input_randomness(vals->type, vals->code, vals->value);
+
/* trigger auto repeat for key events */
- if (type == EV_KEY && value != 2) {
- if (value)
- input_start_autorepeat(dev, code);
- else
- input_stop_autorepeat(dev);
+ for (v = vals; v != vals + count; v++) {
+ if (v->type == EV_KEY && v->value != 2) {
+ if (v->value)
+ input_start_autorepeat(dev, v->code);
+ else
+ input_stop_autorepeat(dev);
+ }
}
+}
+
+static void input_pass_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ struct input_value vals[] = { { type, code, value } };
+ input_pass_values(dev, vals, 1);
}
/*
@@ -146,18 +181,12 @@ static void input_repeat_key(unsigned long data) if (test_bit(dev->repeat_key, dev->key) && is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {+ struct input_value vals[] = {+ { EV_KEY, dev->repeat_key, 2 },+ { EV_SYN, SYN_REPORT, 1 },+ };- input_pass_event(dev, EV_KEY, dev->repeat_key, 2);-- if (dev->sync) {- /*- * Only send SYN_REPORT if we are not in a middle- * of driver parsing a new hardware packet.- * Otherwise assume that the driver will send- * SYN_REPORT once it's done.- */- input_pass_event(dev, EV_SYN, SYN_REPORT, 1);- }+ input_pass_values(dev, vals, 2); if (dev->rep[REP_PERIOD]) mod_timer(&dev->timer, jiffies +
@@ -170,37 +199,23 @@ static void input_repeat_key(unsigned long data) #define INPUT_IGNORE_EVENT 0 #define INPUT_PASS_TO_HANDLERS 1 #define INPUT_PASS_TO_DEVICE 2+#define INPUT_FLUSH 4 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) static int input_handle_abs_event(struct input_dev *dev, unsigned int code, int *pval) { bool is_mt_event;- int *pold;-- if (code == ABS_MT_SLOT) {- /*- * "Stage" the event; we'll flush it later, when we- * get actual touch data.- */- if (dev->mt && *pval >= 0 && *pval < dev->mt->num_slots)- dev->slot = *pval;-- return INPUT_IGNORE_EVENT;- }+ int *pold = NULL; is_mt_event = input_is_mt_value(code); if (!is_mt_event) { pold = &dev->absinfo[code].value; } else if (dev->mt) {- pold = &dev->mt->slots[dev->slot].abs[code - ABS_MT_FIRST];- } else {- /*- * Bypass filtering for multi-touch events when- * not employing slots.- */- pold = NULL;+ int slot = dev->absinfo[ABS_MT_SLOT].value;+ if (slot >= 0 && slot < dev->mt->num_slots)+ pold = &dev->mt->slots[slot].abs[code - ABS_MT_FIRST]; } if (pold) {
@@ -212,17 +227,11 @@ static int input_handle_abs_event(struct input_dev *dev, *pold = *pval; }- /* Flush pending "slot" event */- if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {- input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);- input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);- }- return INPUT_PASS_TO_HANDLERS; }-static void input_handle_event(struct input_dev *dev,- unsigned int type, unsigned int code, int value)+static int input_get_disposition(struct input_dev *dev,+ unsigned int type, unsigned int code, int value) { int disposition = INPUT_IGNORE_EVENT;
@@ -326,14 +331,35 @@ static void input_handle_event(struct input_dev *dev, break; }- if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)- dev->sync = false;+ return disposition;+}++static void input_handle_event(struct input_dev *dev,+ unsigned int type, unsigned int code, int value)+{+ struct input_value *v;+ int disp;++ disp = input_get_disposition(dev, type, code, value);- if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)+ if ((disp & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value);- if (disposition & INPUT_PASS_TO_HANDLERS)- input_pass_event(dev, type, code, value);+ if (!dev->vals)+ return;++ if (disp & INPUT_PASS_TO_HANDLERS) {+ v = &dev->vals[dev->num_vals++];+ v->type = type;+ v->code = code;+ v->value = value;+ }++ if ((disp & INPUT_FLUSH) || (dev->num_vals >= dev->max_vals)) {+ if (dev->num_vals >= 2)
I'm not sure about this check. What if the previous "frame" had
dev->max_vals + 1 events, and so dev->max_vals of them (all but the
SYN_REPORT) were already passed.
We would not get that frame's SYN_REPORT all by itself, so "disp &
INPUT_FLUSH" is true, but dev->num_vals == 1. We still want to pass
the SYN_REPORT immediately, and not save until we get another full
frame.
Is this even possible?
How could this already be non-NULL? Is it possible to re-register a device?
A huge optimization to input event processing is pretty exciting!
-Daniel
quoted hunk
+ dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+ if (!dev->vals)
+ return -ENOMEM;
+
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Daniel Kurtz <hidden> Date: 2012-08-24 04:07:49
On Mon, Aug 13, 2012 at 5:42 AM, Henrik Rydberg [off-list ref] wrote:
quoted hunk
By sending a full frame of events at the same time, the irqsoff
latency at heavy load is brought down from 200 us to 100 us.
Signed-off-by: Henrik Rydberg <redacted>
---
drivers/input/evdev.c | 68 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 47 insertions(+), 21 deletions(-)
@@ -54,16 +54,9 @@ struct evdev_client {staticstructevdev*evdev_table[EVDEV_MINORS];staticDEFINE_MUTEX(evdev_table_mutex);-staticvoidevdev_pass_event(structevdev_client*client,-structinput_event*event,-ktime_tmono,ktime_treal)+staticvoid__pass_event(structevdev_client*client,+conststructinput_event*event){-event->time=ktime_to_timeval(client->clkid==CLOCK_MONOTONIC?-mono:real);--/* Interrupts are disabled, just acquire the lock. */-spin_lock(&client->buffer_lock);-client->buffer[client->head++]=*event;client->head&=client->bufsize-1;
@@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client,client->packet_head=client->head;kill_fasync(&client->fasync,SIGIO,POLL_IN);}+}++staticvoidevdev_pass_values(structevdev_client*client,+conststructinput_value*vals,size_tcount,+ktime_tmono,ktime_treal)+{+structevdev*evdev=client->evdev;+conststructinput_value*v;+structinput_eventevent;+boolwakeup=false;++event.time=ktime_to_timeval(client->clkid==CLOCK_MONOTONIC?+mono:real);++/* Interrupts are disabled, just acquire the lock. */+spin_lock(&client->buffer_lock);++for(v=vals;v!=vals+count;v++){+event.type=v->type;+event.code=v->code;+event.value=v->value;+__pass_event(client,&event);+if(v->type==EV_SYN&&v->code==SYN_REPORT)+wakeup=true;+}spin_unlock(&client->buffer_lock);++if(wakeup)+wake_up_interruptible(&evdev->wait);}/*-*Passincomingeventtoallconnectedclients.+*Passincomingeventstoallconnectedclients.*/-staticvoidevdev_event(structinput_handle*handle,-unsignedinttype,unsignedintcode,intvalue)+staticvoidevdev_events(structinput_handle*handle,+conststructinput_value*vals,size_tcount){structevdev*evdev=handle->private;structevdev_client*client;-structinput_eventevent;ktime_ttime_mono,time_real;time_mono=ktime_get();time_real=ktime_sub(time_mono,ktime_get_monotonic_offset());-event.type=type;-event.code=code;-event.value=value;-rcu_read_lock();client=rcu_dereference(evdev->grab);if(client)-evdev_pass_event(client,&event,time_mono,time_real);+evdev_pass_values(client,vals,count,time_mono,time_real);elselist_for_each_entry_rcu(client,&evdev->client_list,node)-evdev_pass_event(client,&event,time_mono,time_real);+evdev_pass_values(client,vals,count,+time_mono,time_real);
Hi Henrik,
Reading the time just once and applying it as the timestamp to an
entire frame is very nice.
However, is it ever possible for the SYN_REPORT to get delayed until
the next batch of input_values, therefore breaking the assumption that
the SYN_REPORT timestamp applies to the rest of the input_values for
its frame?
Also, bonus points if the input driver could set this input frame
timestamp based on when it first saw a hardware interrupt rather then
when evdev gets around to sending the frame to userspace. This could
potentially remove a lot of the timing jitter userspace sees when
computing ballistics based on input event timestamps.
Thanks!
-Daniel
quoted hunk
rcu_read_unlock();
+}
- if (type == EV_SYN && code == SYN_REPORT)
- wake_up_interruptible(&evdev->wait);
+/*
+ * Pass incoming event to all connected clients.
+ */
+static void evdev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
+{
+ struct input_value vals[] = { { type, code, value } };
+
+ evdev_events(handle, vals, 1);
}
static int evdev_fasync(int fd, struct file *file, int on)
1.7.11.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Henrik Rydberg <hidden> Date: 2012-08-25 19:33:38
Hi Daniel,
On Mon, Aug 13, 2012 at 5:42 AM, Henrik Rydberg [off-list ref] wrote:
quoted
On heavy event loads, such as a multitouch driver, the irqsoff latency
can be as high as 250 us. By accumulating a frame worth of data
before passing it on, the latency can be dramatically reduced. As a
side effect, the special EV_SYN handling can be removed, since the
frame is now atomic.
This patch(set) is very interesting and exciting. Thanks!
Some questions and comments inline...
quoted
This patch adds the events() handler callback and uses it if it
exists. The latency is improved by 50 us even without the callback.
How much of the savings is just from reducing the number of
add_input_randomness() calls from 1-per-input_value to 1-per-frame?
Some, but the largest saving comes from calling down to evdev more sparsely.
Could you achieve similar savings by only calling add_input_randomness
on the first input_value after each EV_SYN/SYN_REPORT (ie "when sync =
true")?
It might make a bit of a difference, because of the additional locks,
but I have not tried it explicitly.
quoted
@@ -90,46 +90,81 @@ static void input_stop_autorepeat(struct input_dev *dev) * filtered out, through all open handles. This function is called with * dev->event_lock held and interrupts disabled. */-static void input_pass_event(struct input_dev *dev,- unsigned int type, unsigned int code, int value)+static size_t input_to_handler(struct input_handle *handle,+ struct input_value *vals, size_t count)
The only thing that is a little strange with this function is that it
actually changes the 'vals' array due to in-place filtering.
Hm, yes, I did not want to allocate additional memory for the
filtering stuff. It is only used in a few (one?) place, and TBH, it is
not on my list of favorite pieces of code. I would rather see that
api modified than working towards more elaborate filtering schemes.
It means
that input_to_handler can't handle const arrays of vals, which may
have a performance impact in some cases (like key repeat). You are
relying on this behavior since you want to pass the final filtered
input_value array to ->events() without copying, but this seems to be
optimizing the 'filtered' case relative to the (normal?) unfiltered
behavior. Probably not worth changing, though.
Maybe we can have a handler->filter_events(handle, vals, count) that
returns the number of events left after filtering.
This would allow more sophisticated filtering that could inspect an
entire frame.
Possibly. Still, the notion of filtering as information-sharing
between drivers on the input bus is not one of my favorites. IMHO,
focus should be on getting the data out of the kernel as quickly as
possible.
In the original version, one handler would not call both ->filter()
and ->event().
I'm not sure if that was a bug or a feature. But, you now make it possible.
However, this opens up the possibility of a filter handler processing
events via its ->event that would get filtered out by a later
handler's filter.
True, but it does not change any of the existing usages of filtering.
In sum, I think if we assume a handler only has either ->filter or
->event (->events), then we can split this function into two, one that
only does filtering on filters, and one that only passes the resulting
filtered events.
quoted
+ if (handler->events)
+ handler->events(handle, vals, count);
+ else
+ for (v = vals; v != end; v++)
+ handler->event(handle, v->type, v->code, v->value);
+
+ return count;
+}
My standpoint is clear by now, so I shall not repeat myself. :-)
quoted
@@ -326,14 +331,35 @@ static void input_handle_event(struct input_dev *dev, break; }- if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)- dev->sync = false;+ return disposition;+}++static void input_handle_event(struct input_dev *dev,+ unsigned int type, unsigned int code, int value)+{+ struct input_value *v;+ int disp;++ disp = input_get_disposition(dev, type, code, value);- if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)+ if ((disp & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value);- if (disposition & INPUT_PASS_TO_HANDLERS)- input_pass_event(dev, type, code, value);+ if (!dev->vals)+ return;++ if (disp & INPUT_PASS_TO_HANDLERS) {+ v = &dev->vals[dev->num_vals++];+ v->type = type;+ v->code = code;+ v->value = value;+ }++ if ((disp & INPUT_FLUSH) || (dev->num_vals >= dev->max_vals)) {+ if (dev->num_vals >= 2)
I'm not sure about this check. What if the previous "frame" had
dev->max_vals + 1 events, and so dev->max_vals of them (all but the
SYN_REPORT) were already passed.
We would not get that frame's SYN_REPORT all by itself, so "disp &
INPUT_FLUSH" is true, but dev->num_vals == 1. We still want to pass
the SYN_REPORT immediately, and not save until we get another full
frame.
Is this even possible?
Yes, it is possible, if the driver is misconfigured with respect to
the input buffer size. I have ignored that possibility in a few other
places as well (keyboard repeat for one). You are probably right in
that it should be handled somehow, but I would rather make sure the
buffer is always large enough. The atomicity of the frame is really
what makes things go faster.
From: Henrik Rydberg <hidden> Date: 2012-08-25 19:41:08
Reading the time just once and applying it as the timestamp to an
entire frame is very nice.
However, is it ever possible for the SYN_REPORT to get delayed until
the next batch of input_values, therefore breaking the assumption that
the SYN_REPORT timestamp applies to the rest of the input_values for
its frame?
Yes, but see reply to previous patch.
Also, bonus points if the input driver could set this input frame
timestamp based on when it first saw a hardware interrupt rather then
when evdev gets around to sending the frame to userspace. This could
potentially remove a lot of the timing jitter userspace sees when
computing ballistics based on input event timestamps.
In principle, yes (it has been discussed before), but in practise some
devices provide timestamps and some not, and the scale and granularity
may vary. In addition, desktop userland (read X input) does not even
use the kernel timestamp, so the effect would not even be seen without
a synchronized effort. I am not saying it is a bad idea, but it has
some details to get straight before it becomes useful.
Thanks,
Henrik
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
Signed-off-by: Henrik Rydberg <redacted>
---
Hi Benjamin,
Maybe this patch works better? It has received limited testing so far.
What is the status of this patch please? Henrik, Benjamin?
@@ -56,7 +56,6 @@ struct mt_slot {__s32x,y,p,w,h;__s32contactid;/* the device ContactID assigned to this slot */booltouch_state;/* is the touch valid? */-boolseen_in_this_frame;/* has this slot been updated */};structmt_class{
@@ -93,7 +92,7 @@ struct mt_device {*1meansweshoulduseaserialprotocol*>1meanshybrid(multitouch)protocol*/boolcurvalid;/* is the current contact valid? */-structmt_slot*slots;+unsignedmt_flags;/* flags to pass to input-mt */};/* classes of device behavior */
@@ -134,25 +133,6 @@ static int cypress_compute_slot(struct mt_device *td)return-1;}-staticintfind_slot_from_contactid(structmt_device*td)-{-inti;-for(i=0;i<td->maxcontacts;++i){-if(td->slots[i].contactid==td->curdata.contactid&&-td->slots[i].touch_state)-returni;-}-for(i=0;i<td->maxcontacts;++i){-if(!td->slots[i].seen_in_this_frame&&-!td->slots[i].touch_state)-returni;-}-/* should not occurs. If this happens that means-*thatthedevicesentmoretouchesthatitsays-*inthereportdescriptor.Itisignoredthen.*/-return-1;-}-staticstructmt_classmt_classes[]={{.name=MT_CLS_DEFAULT,.quirks=MT_QUIRK_NOT_SEEN_MEANS_UP},
@@ -319,24 +299,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,*Weneedtoignorefieldsthatbelongtoothercollections*suchasMousethatmighthavethesameGenericDesktopusages.*/if(field->application==HID_DG_TOUCHSCREEN)-set_bit(INPUT_PROP_DIRECT,hi->input->propbit);+td->mt_flags|=INPUT_MT_DIRECT;elseif(field->application!=HID_DG_TOUCHPAD)return0;-/* In case of an indirect device (touchpad), we need to add-*specificBTN_TOOL_*tobehandledbythesynapticsxorg-*driver.-*Wealsoconsiderthattouchscreensprovidingbuttonsaretouchpads.+/*+*Modeltouchscreensprovidingbuttonsastouchpads.*/if(field->application==HID_DG_TOUCHPAD||-(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON||-cls->is_indirect){-set_bit(INPUT_PROP_POINTER,hi->input->propbit);-set_bit(BTN_TOOL_FINGER,hi->input->keybit);-set_bit(BTN_TOOL_DOUBLETAP,hi->input->keybit);-set_bit(BTN_TOOL_TRIPLETAP,hi->input->keybit);-set_bit(BTN_TOOL_QUADTAP,hi->input->keybit);-}+(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON)+td->mt_flags|=INPUT_MT_POINTER;/* eGalax devices provide a Digitizer.Stylus input which overrides*thecorrectDigitizers.FingerX/Yranges.
From: Benjamin Tissoires <hidden> Date: 2012-08-29 13:36:43
Hi Jiri,
On Wed, Aug 29, 2012 at 12:25 AM, Jiri Kosina [off-list ref] wrote:
On Wed, 22 Aug 2012, Henrik Rydberg wrote:
quoted
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
Signed-off-by: Henrik Rydberg <redacted>
---
Hi Benjamin,
Maybe this patch works better? It has received limited testing so far.
What is the status of this patch please? Henrik, Benjamin?
Well, Henrik submitted a new release a few days ago (including this version).
I just didn't found the time to test the whole thing on our different devices.
It's now on the top of my TODO list.
Cheers,
Benjamin
@@ -56,7 +56,6 @@ struct mt_slot {__s32x,y,p,w,h;__s32contactid;/* the device ContactID assigned to this slot */booltouch_state;/* is the touch valid? */-boolseen_in_this_frame;/* has this slot been updated */};structmt_class{
@@ -93,7 +92,7 @@ struct mt_device {*1meansweshoulduseaserialprotocol*>1meanshybrid(multitouch)protocol*/boolcurvalid;/* is the current contact valid? */-structmt_slot*slots;+unsignedmt_flags;/* flags to pass to input-mt */};/* classes of device behavior */
@@ -134,25 +133,6 @@ static int cypress_compute_slot(struct mt_device *td)return-1;}-staticintfind_slot_from_contactid(structmt_device*td)-{-inti;-for(i=0;i<td->maxcontacts;++i){-if(td->slots[i].contactid==td->curdata.contactid&&-td->slots[i].touch_state)-returni;-}-for(i=0;i<td->maxcontacts;++i){-if(!td->slots[i].seen_in_this_frame&&-!td->slots[i].touch_state)-returni;-}-/* should not occurs. If this happens that means-*thatthedevicesentmoretouchesthatitsays-*inthereportdescriptor.Itisignoredthen.*/-return-1;-}-staticstructmt_classmt_classes[]={{.name=MT_CLS_DEFAULT,.quirks=MT_QUIRK_NOT_SEEN_MEANS_UP},
@@ -319,24 +299,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,*Weneedtoignorefieldsthatbelongtoothercollections*suchasMousethatmighthavethesameGenericDesktopusages.*/if(field->application==HID_DG_TOUCHSCREEN)-set_bit(INPUT_PROP_DIRECT,hi->input->propbit);+td->mt_flags|=INPUT_MT_DIRECT;elseif(field->application!=HID_DG_TOUCHPAD)return0;-/* In case of an indirect device (touchpad), we need to add-*specificBTN_TOOL_*tobehandledbythesynapticsxorg-*driver.-*Wealsoconsiderthattouchscreensprovidingbuttonsaretouchpads.+/*+*Modeltouchscreensprovidingbuttonsastouchpads.*/if(field->application==HID_DG_TOUCHPAD||-(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON||-cls->is_indirect){-set_bit(INPUT_PROP_POINTER,hi->input->propbit);-set_bit(BTN_TOOL_FINGER,hi->input->keybit);-set_bit(BTN_TOOL_DOUBLETAP,hi->input->keybit);-set_bit(BTN_TOOL_TRIPLETAP,hi->input->keybit);-set_bit(BTN_TOOL_QUADTAP,hi->input->keybit);-}+(usage->hid&HID_USAGE_PAGE)==HID_UP_BUTTON)+td->mt_flags|=INPUT_MT_POINTER;/* eGalax devices provide a Digitizer.Stylus input which overrides*thecorrectDigitizers.FingerX/Yranges.
With the input_mt_sync_frame() function in place, there is no longer
any need to keep the full touch state in the driver. This patch
removes the slot state and replaces the lookup code with the input-mt
equivalent. The initialization code is moved to mt_input_configured(),
to make sure the full HID report has been seen.
Signed-off-by: Henrik Rydberg <redacted>
---
Hi Benjamin,
Maybe this patch works better? It has received limited testing so far.
What is the status of this patch please? Henrik, Benjamin?
Well, Henrik submitted a new release a few days ago (including this version).
I just didn't found the time to test the whole thing on our different devices.
It's now on the top of my TODO list.
Ah, I have missed the fact that this one is also part of Henrik's series,
sorry for the noise.
I haven't unfortunately reviewed the series yet due to kernel summit &
related events, but I'll get to it shortly.
Thanks,
--
Jiri Kosina
SUSE Labs