diff --git a/src/evdev.c b/src/evdev.c
index a5cd32b..baa00f8 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -123,7 +123,6 @@ static void EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev);
 static void EvdevCopyFromData(InputInfoPtr pInfo, EvdevDataMTPtr pData);
 static void EvdevReinitPEvdev(InputInfoPtr pInfo);
 static void EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev);
-static void EvdevEndOfMultiTouch(InputInfoPtr pInfo,EvdevDataMTPtr pData);
 static void EvdevSetMultitouch(InputInfoPtr pInfo, int num_multitouch);
 static InputInfoPtr EvdevCreateSubDevice(InputInfoPtr pInfo, int id);
 static void EvdevDeleteSubDevice(InputInfoPtr pInfo, InputInfoPtr subdev);
@@ -360,6 +359,16 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
     }
 }
 
+static void
+EvdevSetSubdevID (EvdevSubdevInfoPtr pSubdevInfo, int id)
+{
+     if (pSubdevInfo->id != id) {
+          pSubdevInfo->id = id;
+          XIChangeDeviceProperty(pSubdevInfo->pInfo->dev, prop_tracking_id, XA_INTEGER, 32,
+                                 PropModeReplace, 1, &pSubdevInfo->id, TRUE);
+     }
+}
+
 /**
  * 
  */
@@ -368,16 +377,18 @@ EvdevSubdevTimer(OsTimerPtr timer, CARD32 time, pointer arg)
 {
     InputInfoPtr pInfo = (InputInfoPtr)arg;
     EvdevPtr pEvdev = pInfo->private;
+    EvdevSubdevInfoPtr pSubdevInfo;
     int i;
-    
-    for (i=0;i<pEvdev->num_multitouch;i++) {
-        if (pEvdev->vals_mt[i].containsValues) {
-            EvdevEndOfMultiTouch(pInfo, &(pEvdev->vals_mt[i]));
-        }
+
+    for (i=0;i<pEvdev->num_multitouch;++i) {
+         pSubdevInfo = &pEvdev->subdev_info[i];
+
+         if (pSubdevInfo->id >= 0) {
+              EvdevSetSubdevID (pSubdevInfo, -1);
+         }
     }
-    
+
     return 0;
-    //return pEvdev->timeout; /* come back in 100 ms */
 }
 
 /**
@@ -635,6 +646,7 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
         return;
 
     pEvdev->vals[pEvdev->axis_map[ev->code]] = value;
+
     if (ev->code == ABS_X)
         pEvdev->abs |= ABS_X_VALUE;
     else if (ev->code == ABS_Y)
@@ -688,64 +700,188 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
     }
 }
 
-static void EvdevEndOfMultiTouch(InputInfoPtr pInfo,EvdevDataMTPtr pData) {
-    InputInfoPtr pSubdev = pData->pInfo;
-    EvdevPtr pEvdevSubdev = pSubdev->private;
-    pEvdevSubdev->id = -1;
-    XIChangeDeviceProperty(pSubdev->dev, prop_tracking_id, XA_INTEGER, 32,
-        PropModeReplace, 1, &(pEvdevSubdev->id), TRUE);
-    
-    pData->containsValues = FALSE;
-    pData->id = -1;
+static EvdevSubdevInfoPtr
+EvdevFindClosestSubdevInfo (InputInfoPtr pInfo, int x, int y, int *distance)
+{
+     EvdevPtr pEvdev = pInfo->private, pEvdevSubdev;
+     EvdevSubdevInfoPtr subdev = NULL, pSubdevInfo;
+     int old_x, old_y, xd, yd, i;
+     int dist, min_distance = MAXINT;
+
+     for(i=0;i<pEvdev->num_multitouch;++i) {
+          pSubdevInfo = &pEvdev->subdev_info[i];
+
+          if (!pSubdevInfo->used)
+               continue;
+
+          pEvdevSubdev = pSubdevInfo->pInfo->private;
+
+          old_x = pEvdevSubdev->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
+          old_y = pEvdevSubdev->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
+
+          xd = x - old_x;
+          if (xd < 0)
+               xd *= -1;
+
+          yd = y - old_y;
+          if (yd < 0)
+               yd *= -1;
+
+          dist = xd + yd;
+
+          if (dist < min_distance) {
+               min_distance = dist;
+               subdev = pSubdevInfo;
+          }
+     }
+
+     *distance = min_distance;
+
+     return subdev;
+}
+
+static EvdevSubdevInfoPtr
+EvdevFindUnallocatedSubdev (InputInfoPtr pInfo)
+{
+     EvdevPtr pEvdev = pInfo->private;
+     EvdevSubdevInfoPtr pSubdevInfo;
+     int i;
+
+     for (i=0;i<pEvdev->num_multitouch;++i) {
+          pSubdevInfo = &pEvdev->subdev_info[i];
+
+          if (!pSubdevInfo->used) {
+               pSubdevInfo->used = TRUE;
+               pSubdevInfo->distance = 0;
+               return pSubdevInfo;
+          }
+     }
+
+     return NULL;
 }
 
 /**
- * Post the multtouch motion events.
+ * Post the multitouch motion events.
  */
 static void
 EvdevPostMTMotionEvents(InputInfoPtr pInfo,struct input_event *ev)
 {
     EvdevPtr pEvdev = pInfo->private, pEvdevSubdev;
     EvdevDataMTPtr pData;
-    InputInfoPtr pSubdev;
-    Time currentTime = GetTimeInMillis();
-    int i;
+    int i, j, x, y, distance;
+    EvdevSubdevInfoPtr pSubdevInfo, subdev_map[MAX_VALUATORS_MT] = { 0 };
 
     for (i=0;i<pEvdev->num_multitouch;++i) {
-        pData = &(pEvdev->vals_mt[i]);
-        if (!pData->containsValues) {
-            continue;
-        }
-        pSubdev = pData->pInfo;
-        if (!pSubdev)
-            continue;
+         pData = &pEvdev->vals_mt[i];
+
+         if (!pData->assigned)
+              break;
+
+         x = pData->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
+         y = pData->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
+
+         pSubdevInfo = EvdevFindClosestSubdevInfo (pInfo, x, y, &distance);
+
+         if (!pSubdevInfo) {
+              /* There was no old data to compare, this is the very first event */
+              pSubdevInfo = EvdevFindUnallocatedSubdev (pInfo);
+              pData->new_device_assigned = TRUE;
+              distance = 0;
+         }
+
+         if (!pSubdevInfo) {
+              xf86Msg(X_WARNING, "No free subdev for MT event. %s:%d\n",__FILE__,__LINE__);
+              subdev_map[i] = NULL;
+              continue;
+         }
+
+         /* Subdev was already used */
+         if (pSubdevInfo->distance >= 0) {
+              if (pSubdevInfo->distance <= distance) {
+                   pSubdevInfo = EvdevFindUnallocatedSubdev (pInfo);
+                   pData->new_device_assigned = TRUE;
+              } else {
+                   /* This is purely heuristic. Given event granularity and finger size,
+                    * it is quite likely that if a device was wrongly assigned before to
+                    * a MT event, it's due to it being a new touch on the screen being
+                    * missassigned before the right MT event for the device (i.e. this one)
+                    * is processed. So it should be reassigned, and a new subdev should
+                    * be used for the older MT event.
+                    */
+                   for (j=0;j<i;++j) {
+                        if (subdev_map[j] == pSubdevInfo) {
+                             subdev_map[j] = EvdevFindUnallocatedSubdev (pInfo);
+                             pData->new_device_assigned = TRUE;
+                        }
+                   }
+              }
+         }
+
+         subdev_map[i] = pSubdevInfo;
+
+         if (pSubdevInfo)
+              pSubdevInfo->distance = distance;
+    }
+
+    /* Now actually process the MT events */
+    for (i=0;i<pEvdev->num_multitouch;++i) {
+         pData = &pEvdev->vals_mt[i];
+         pSubdevInfo = subdev_map[i];
 
+         if (!pData->assigned)
+              break;
 
-        if (currentTime > pData->expires) {
-            /* 
-             * the MT-touch has ended, destroy the subdevice
-             */
-            EvdevEndOfMultiTouch(pInfo, pData);
-            continue;
-        }
-        
-        EvdevCopyFromData(pSubdev, pData);
-        pEvdevSubdev = pSubdev->private;
-        if (pEvdevSubdev->id != pData->id) {
-            pEvdevSubdev->id = pData->id;
-            XIChangeDeviceProperty(pSubdev->dev, prop_tracking_id, XA_INTEGER, 32,
-            PropModeReplace, 1, &(pEvdevSubdev->id), TRUE);
-        }
-        pEvdevSubdev->mt = 0;
-        pEvdevSubdev->abs = 1;
-        pEvdevSubdev->rel = 0;
-        pEvdevSubdev->tool = 1;
-        /* droping of the pressed/released events */
-        memset(pEvdevSubdev->queue, 0, sizeof(pEvdevSubdev->queue));
-        pEvdevSubdev->num_queue = 0;
-        EvdevProcessSyncEvent(pSubdev, ev);
-        
+         if (!pSubdevInfo) {
+              xf86Msg(X_WARNING, "MT Event has no matching subdevice. %s:%d\n",__FILE__,__LINE__);
+              continue;
+         }
+
+         EvdevCopyFromData(pSubdevInfo->pInfo, pData);
+         pEvdevSubdev = pSubdevInfo->pInfo->private;
+
+         if (!pData->new_device_assigned) {
+              if (pSubdevInfo->id < 0) {
+                   int z;
+
+                   for (z=0;z<pEvdev->num_multitouch;++z) {
+                        if (pSubdevInfo == &pEvdev->subdev_info[z])
+                             break;
+                   }
+
+                   EvdevSetSubdevID (pSubdevInfo, z);
+              }
+
+              pEvdevSubdev->mt = 0;
+              pEvdevSubdev->abs = 1;
+              pEvdevSubdev->rel = 0;
+              pEvdevSubdev->tool = 1;
+              /* dropping of the pressed/released events */
+              memset(pEvdevSubdev->queue, 0, sizeof(pEvdevSubdev->queue));
+              pEvdevSubdev->num_queue = 0;
+
+              EvdevProcessSyncEvent(pSubdevInfo->pInfo, ev);
+         }
     }
+
+    /* Now reset all data */
+    for (i=0;i<pEvdev->num_multitouch;++i) {
+         pEvdev->vals_mt[i].assigned = FALSE;
+         pEvdev->vals_mt[i].new_device_assigned = FALSE;
+
+         pSubdevInfo = &pEvdev->subdev_info[i];
+
+         if (pSubdevInfo->distance < 0) {
+              /* Device was unused */
+              pSubdevInfo->used = FALSE;
+
+              if (pSubdevInfo->id >= 0) {
+                   EvdevSetSubdevID (pSubdevInfo, -1);
+              }
+         }
+
+         pSubdevInfo->distance = -1;
+    }
+
     pEvdev->subdevice_timer = TimerSet(pEvdev->subdevice_timer, 0, pEvdev->timeout, EvdevSubdevTimer, pInfo);
 }
 
@@ -819,23 +955,43 @@ EvdevCopyFromData(InputInfoPtr pInfo, EvdevDataMTPtr pData) {
 }
 
 static void
-EvdevStoreMTData(InputInfoPtr pInfo, EvdevDataMTPtr pData) {
+EvdevStoreMTData(InputInfoPtr pInfo) {
     EvdevPtr pEvdev = pInfo->private;
-    int id,x,y;
-    Time currentTime = GetTimeInMillis();
+    EvdevDataMTPtr pData;
+    int i, x, y;
+
+    for (i=0;i<pEvdev->num_multitouch;++i) {
+         pData = &pEvdev->vals_mt[i];
+
+         if (!pData->assigned)
+              break;
+    }
+
+    if (i > pEvdev->num_multitouch) {
+         xf86Msg(X_WARNING, "ignoring event: not enough space to store it. %s:%d\n", __FILE__,__LINE__);
+         return;
+    }
 
-    id = pEvdev->current_id;
     x = pEvdev->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
     y = pEvdev->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
 
+    /* Hack to reduce noise from the input events */
+#define SENSITIVITY 200
+
+    x = (x / SENSITIVITY) * SENSITIVITY;
+    y = (y / SENSITIVITY) * SENSITIVITY;
 
+#undef SENSITIVITY
 
-    pData->id = id;
+    pData->id = pEvdev->current_id;;
     memcpy(pData->vals, pEvdev->vals, MAX_VALUATORS * sizeof(int));
+
+    pData->vals[pEvdev->axis_map[ABS_MT_POSITION_X]] = x;
+    pData->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]] = y;
     pData->vals[pEvdev->axis_map[ABS_X]] = x;
     pData->vals[pEvdev->axis_map[ABS_Y]] = y;
-    pData->containsValues = TRUE;
-    pData->expires = currentTime + pEvdev->timeout;
+
+    pData->assigned = TRUE;
 }
 
 /**
@@ -846,59 +1002,12 @@ static void
 EvdevProcessMTSyncReport(InputInfoPtr pInfo, struct input_event *ev)
 {
     EvdevPtr pEvdev = pInfo->private;
-    BOOL found = FALSE;
-    int id;
-    int i;
-    
+
     if (!pEvdev->num_multitouch)
         return;
 
-
-    id = pEvdev->current_id;
-    
-    // ntrig doesn't gives the trackID, generating one
-    if (id < 0) {
-        id = pEvdev->num_mt++;
-        pEvdev->current_id = id;
-    }
-    
-    if (id >= 0) { // the trackID is given by the device
-        /* 
-         * find the previously associated pData
-         */
-        i = 0;
-        while (i < pEvdev->num_multitouch && pEvdev->vals_mt[i].id != id) {
-
-            ++i;
-        }
-        if (i < pEvdev->num_multitouch) {
-
-            found = TRUE;
-        }
-    }
-
-    if (!found) {
-        /* 
-         * not found :
-         * find the first available pData
-         */
-        i = 0;
-        while (i < pEvdev->num_multitouch && pEvdev->vals_mt[i].containsValues ) {
-            ++i;
-        }
-        if (i < pEvdev->num_multitouch) {
-
-            found = TRUE;
-        }
-    }
-    
-    if (found) {
-        EvdevStoreMTData(pInfo, &(pEvdev->vals_mt[i]));
-    } else {
-        xf86Msg(X_WARNING, "%s: ignoring event {id=%d} : not enough space to store it. %s:%d\n", pInfo->name,id,__FILE__,__LINE__);
-    }
+    EvdevStoreMTData(pInfo);
     EvdevReinitPEvdev(pInfo);
-    pEvdev->mt = 1;
 }
 
 static void
@@ -910,7 +1019,6 @@ EvdevReinitPEvdev(InputInfoPtr pInfo) {
     pEvdev->abs = 0;
     pEvdev->rel = 0;
     pEvdev->mt = 0;
-    pEvdev->num_mt = 0;
     pEvdev->current_id = -1;
 }
 
@@ -927,12 +1035,13 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
     
     if (ev->code == SYN_MT_REPORT) {
         EvdevProcessMTSyncReport(pInfo, ev);
+        pEvdev->mt = TRUE;
         return;
     }
     
 
     if (pEvdev->mt) {
-        EvdevPostMTMotionEvents(pInfo, ev);
+         EvdevPostMTMotionEvents(pInfo, ev);
     } else {
         EvdevProcessValuators(pInfo, v, &num_v, &first_v);
 
@@ -1913,10 +2022,12 @@ EvdevProc(DeviceIntPtr device, int what)
             /* removing it in the list of the core device */
             g_pEvdev = pEvdev->core_device->private;
             for (i=0; i<MAX_VALUATORS_MT; ++i) {
+#if 0
                 if (g_pEvdev->vals_mt[i].pInfo == pInfo) {
                     g_pEvdev->vals_mt[i].pInfo = NULL;
                     break;
                 }
+#endif
             }
             xf86RemoveEnabledDevice(pInfo);
         }
@@ -2208,14 +2319,13 @@ EvdevProbe(InputInfoPtr pInfo)
         if ((TestBit(ABS_X, pEvdev->abs_bitmask) &&
              TestBit(ABS_Y, pEvdev->abs_bitmask))) {
             xf86Msg(X_INFO, "%s: Found x and y absolute axes\n", pInfo->name);
-            if (TestBit(BTN_TOOL_PEN, pEvdev->key_bitmask))
-            {
-                xf86Msg(X_INFO, "%s: Found absolute tablet.\n", pInfo->name);
-                pEvdev->flags |= EVDEV_TABLET;
-            } else if ((TestBit(ABS_MT_POSITION_X, pEvdev->abs_bitmask) &&
-                        TestBit(ABS_MT_POSITION_Y, pEvdev->abs_bitmask))) {
+            if ((TestBit(ABS_MT_POSITION_X, pEvdev->abs_bitmask) &&
+                 TestBit(ABS_MT_POSITION_Y, pEvdev->abs_bitmask))) {
                 xf86Msg(X_INFO, "%s: Found absolute multitouch tablet.\n", pInfo->name);
                 pEvdev->flags |= EVDEV_MULTITOUCH;
+            } else if (TestBit(BTN_TOOL_PEN, pEvdev->key_bitmask)) {
+                xf86Msg(X_INFO, "%s: Found absolute tablet.\n", pInfo->name);
+                pEvdev->flags |= EVDEV_TABLET;
             } else if (TestBit(ABS_PRESSURE, pEvdev->abs_bitmask) ||
                 TestBit(BTN_TOUCH, pEvdev->key_bitmask)) {
                 if (num_buttons || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
@@ -2320,22 +2430,24 @@ EvdevSetMultitouch(InputInfoPtr pInfo, int num_multitouch) {
     if (num_multitouch < 0)
         num_multitouch = 0;
 
+    if (num_multitouch == pEvdev->num_multitouch)
+         return;
+
     for (i=0;i<num_multitouch;++i) {
-        if (pEvdev->vals_mt[i].pInfo == NULL){
-            pEvdev->vals_mt[i].containsValues = FALSE;
-            pEvdev->vals_mt[i].id = -1;
-            pEvdev->vals_mt[i].pInfo = EvdevCreateSubDevice(pInfo, i);
-        }
+         if (!pEvdev->subdev_info[i].pInfo) {
+              pEvdev->subdev_info[i].pInfo = EvdevCreateSubDevice(pInfo, i);
+              pEvdev->subdev_info[i].id = -1;
+         }
     }
+
     for (i=num_multitouch;i<MAX_VALUATORS_MT;++i) {
-        pEvdev->vals_mt[i].containsValues = FALSE;
-        pEvdev->vals_mt[i].id = -1;
-        if (pEvdev->vals_mt[i].pInfo) {
-            EvdevDeleteSubDevice(pInfo, pEvdev->vals_mt[i].pInfo);
-            pEvdev->vals_mt[i].pInfo = NULL;
-        }
+         if (pEvdev->subdev_info[i].pInfo) {
+              EvdevDeleteSubDevice(pInfo, pEvdev->subdev_info[i].pInfo);
+              pEvdev->subdev_info[i].pInfo = NULL;
+              pEvdev->subdev_info[i].id = -1;
+         }
     }
-    
+
     pEvdev->num_multitouch = num_multitouch;
 }
 
@@ -3094,7 +3206,11 @@ EvdevCreateSubDevice(InputInfoPtr pInfo, int id) {
     EvdevReplaceOption(input_options, "name",name);
 
     pCreatorInfo = pInfo;
-    NewInputDeviceRequest(input_options, &dev);
+    NewInputDeviceRequest(input_options,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 9
+                          NULL,
+#endif
+                          &dev);
     pSubdev = dev->public.devicePrivate;
     pCreatorInfo = NULL;
 
diff --git a/src/evdev.h b/src/evdev.h
index d55d4c9..852a8c6 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -106,15 +106,20 @@ typedef struct {
     int val;		/* State of the key/button; pressed or released. */
 } EventQueueRec, *EventQueuePtr;
 
+typedef struct _EvdevSubdevInfo{
+     BOOL used;
+     InputInfoPtr pInfo;
+     int distance; /* X/Y Distance during MT event generation */
+     int id;
+} EvdevSubdevInfoRec, *EvdevSubdevInfoPtr;
+
 typedef struct _EvdevDataMTRec{
+    BOOL assigned;
+    BOOL new_device_assigned;
     int id;
-    BOOL containsValues;
-    Time expires;
     int vals[MAX_VALUATORS];
-    InputInfoPtr pInfo;
 } EvdevDataMTRec, *EvdevDataMTPtr;
 
-
 /**
  * Evdev device information, including list of current object
  */
@@ -127,6 +132,7 @@ typedef struct {
     int vals[MAX_VALUATORS];
     int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
     EvdevDataMTRec vals_mt[MAX_VALUATORS_MT];
+    EvdevSubdevInfoRec subdev_info[MAX_VALUATORS_MT];
 
     int flags;
     int tool;
@@ -208,6 +214,7 @@ typedef struct {
     int current_id;
     int num_mt;
     int id;
+    int current_mt_event;
     BOOL associated;
 
     InputInfoPtr core_device;
