summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter@cs.unisa.edu.au>2007-04-23 10:08:48 +0930
committerPeter Hutterer <peter@cs.unisa.edu.au>2007-04-23 10:08:48 +0930
commitba65c34068a836ae393565a6a8260a4e96709816 (patch)
tree7bf959c46149514dc73a16f07c1cf54213df95a4
parent9644a4afbfd8ac4cb51facf0409f73f55743d8a3 (diff)
downloadxorg-driver-xf86-input-evdev-ba65c34068a836ae393565a6a8260a4e96709816.tar.gz
Remove driver from list if no device is associated any more.
This effectively stops the driver from hotplugging new devices. Devices have to be added with the dbus hotplugging events.
-rw-r--r--src/evdev.c8
-rw-r--r--src/evdev.h2
-rw-r--r--src/evdev_brain.c62
3 files changed, 69 insertions, 3 deletions
diff --git a/src/evdev.c b/src/evdev.c
index f506997..5455062 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -461,6 +461,14 @@ EvdevCorePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
if (pEvdev->devices && pEvdev->devices->pInfo)
return pEvdev->devices->pInfo;
+ /* In some cases pEvdev->devices is NULL, but on the next
+ * evdevRescanDevices the device suddenly appears. If we return NULL here,
+ * the server will clean up and the sudden appearance of the device will
+ * segfault. We need to remove the driver from the list to avoid this.
+ * No. I don't know why it just appears. (whot)
+ */
+ evdevRemoveDriver(pEvdev);
+
return NULL;
}
diff --git a/src/evdev.h b/src/evdev.h
index c6e9188..81abbb6 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -256,6 +256,8 @@ Bool evdevStart (InputDriverPtr drv);
Bool evdevNewDriver (evdevDriverPtr driver);
Bool evdevGetBits (int fd, evdevBitsPtr bits);
void evdevRemoveDevice (evdevDevicePtr device);
+void evdevDeleteDevice (evdevDevicePtr device);
+void evdevRemoveDriver (evdevDriverPtr device);
int EvdevBtnInit (DeviceIntPtr device);
int EvdevBtnOn (DeviceIntPtr device);
diff --git a/src/evdev_brain.c b/src/evdev_brain.c
index d0d1ac6..03506c4 100644
--- a/src/evdev_brain.c
+++ b/src/evdev_brain.c
@@ -555,16 +555,24 @@ evdevNewDriver (evdevDriverPtr driver)
void
evdevRemoveDevice (evdevDevicePtr pEvdev)
{
- evdevDriverPtr driver;
+ evdevDriverPtr driver, prev;
evdevDevicePtr *device;
- for (driver = evdev_drivers; driver; driver = driver->next) {
+ prev = evdev_drivers;
+
+ for (driver = evdev_drivers; driver; prev = driver, driver = driver->next) {
for (device = &driver->devices; *device; device = &(*device)->next) {
if (*device == pEvdev) {
*device = pEvdev->next;
- xf86DeleteInput(pEvdev->pInfo, 0);
pEvdev->next = NULL;
+ /* driver without device? get rid of it, otherwise it'll
+ * auto-hotplug when a device is plugged in again.
+ */
if (!driver->devices)
+ {
+ evdevDeleteDevice(pEvdev);
+ evdevRemoveDriver(driver);
+ }
return;
}
}
@@ -600,3 +608,51 @@ evdevGetBits (int fd, evdevBitsPtr bits)
return TRUE;
}
+/**
+ * Free memory associated with device.
+ */
+void
+evdevDeleteDevice(evdevDevicePtr pEvdev)
+{
+ /* pEvdev->pInp is freed in xf86DeleteInput() when
+ * DeleteInputDeviceRequest is called. */
+ xfree(pEvdev->name);
+ xfree(pEvdev->phys);
+ xfree(pEvdev->device);
+ xfree(pEvdev);
+}
+
+/**
+ * Remove a driver from the list, free memory.
+ */
+void evdevRemoveDriver(evdevDriverPtr drv)
+{
+ evdevDriverPtr driver, prev;
+ evdevDevicePtr device;
+
+ if (drv == evdev_drivers)
+ evdev_drivers = evdev_drivers->next;
+ else
+ for (prev = evdev_drivers, driver = prev->next; driver;
+ prev = driver, driver = driver->next)
+ {
+ if (driver == drv)
+ {
+ prev->next = driver->next;
+ }
+ }
+
+ xfree(drv->name);
+ xfree(drv->phys);
+ xfree(drv->device);
+
+ device = drv->devices;
+ while(device)
+ {
+ evdevDeleteDevice(device);
+ device = device->next;
+ }
+
+ xfree(drv);
+}
+