[PATCH 09/36] xfree86: add platform bus hotplug support (v3)
Dave Airlie
airlied at gmail.com
Thu Jul 5 08:21:10 PDT 2012
From: Dave Airlie <airlied at redhat.com>
This provides add/remove support for platform devices at xfree86 ddx level.
v2: cleanup properly if no driver found.
v3: load the modesetting driver before checking driver list.
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
hw/xfree86/common/xf86platformBus.c | 103 ++++++++++++++++++++++++++++
hw/xfree86/common/xf86platformBus.h | 5 ++
hw/xfree86/os-support/linux/lnx_platform.c | 49 +++++++++++++
3 files changed, 157 insertions(+)
diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
index 50b7636..0cc6c0a 100644
--- a/hw/xfree86/common/xf86platformBus.c
+++ b/hw/xfree86/common/xf86platformBus.c
@@ -376,4 +376,107 @@ xf86platformProbeDev(DriverPtr drvp)
return foundScreen;
}
+int
+xf86platformAddDevice(int index)
+{
+ int i, old_screens, scr_index;
+ DriverPtr drvp = NULL;
+ int entity;
+ screenLayoutPtr layout;
+ static char *hotplug_driver_name = "modesetting";
+
+ /* force load the driver for now */
+ xf86LoadOneModule(hotplug_driver_name, NULL);
+
+ for (i = 0; i < xf86NumDrivers; i++) {
+ if (!xf86DriverList[i])
+ continue;
+
+ if (!strcmp(xf86DriverList[i]->driverName, hotplug_driver_name)) {
+ drvp = xf86DriverList[i];
+ break;
+ }
+ }
+ if (i == xf86NumDrivers)
+ return -1;
+
+ old_screens = xf86NumGPUScreens;
+ entity = xf86ClaimPlatformSlot(&xf86_platform_devices[index],
+ drvp, 0, 0, 0);
+ if (!drvp->platformProbe(drvp, entity, PLATFORM_PROBE_GPU_SCREEN, &xf86_platform_devices[index], 0)) {
+ xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
+ }
+ if (old_screens == xf86NumGPUScreens)
+ return -1;
+ i = old_screens;
+
+ for (layout = xf86ConfigLayout.screens; layout->screen != NULL;
+ layout++) {
+ xf86GPUScreens[i]->confScreen = layout->screen;
+ break;
+ }
+
+ if (xf86GPUScreens[i]->PreInit &&
+ xf86GPUScreens[i]->PreInit(xf86GPUScreens[i], 0))
+ xf86GPUScreens[i]->configured = TRUE;
+
+ if (!xf86GPUScreens[i]->configured) {
+ ErrorF("hotplugged device %d didn't configure\n", i);
+ xf86DeleteScreen(xf86GPUScreens[i]);
+ return -1;
+ }
+
+ scr_index = AddGPUScreen(xf86GPUScreens[i]->ScreenInit, 0, NULL);
+
+ dixSetPrivate(&xf86GPUScreens[i]->pScreen->devPrivates,
+ xf86ScreenKey, xf86GPUScreens[i]);
+
+ CreateScratchPixmapsForScreen(xf86GPUScreens[i]->pScreen);
+
+ return 0;
+}
+
+void
+xf86platformRemoveDevice(int index)
+{
+ EntityPtr entity;
+ int ent_num, i, j;
+ Bool found;
+
+ for (ent_num = 0; ent_num < xf86NumEntities; ent_num++) {
+ entity = xf86Entities[ent_num];
+ if (entity->bus.type == BUS_PLATFORM &&
+ entity->bus.id.plat == &xf86_platform_devices[index])
+ break;
+ }
+ if (ent_num == xf86NumEntities)
+ goto out;
+
+ found = FALSE;
+ for (i = 0; i < xf86NumGPUScreens; i++) {
+ for (j = 0; j < xf86GPUScreens[i]->numEntities; j++)
+ if (xf86GPUScreens[i]->entityList[j] == ent_num) {
+ found = TRUE;
+ break;
+ }
+ if (found)
+ break;
+ }
+ if (!found) {
+ ErrorF("failed to find screen to remove\n");
+ goto out;
+ }
+
+ xf86GPUScreens[i]->pScreen->CloseScreen(xf86GPUScreens[i]->pScreen);
+
+ RemoveGPUScreen(xf86GPUScreens[i]->pScreen);
+ xf86DeleteScreen(xf86GPUScreens[i]);
+
+ xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
+
+ xf86_remove_platform_device(index);
+
+ out:
+ return;
+}
#endif
diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h
index 15a3022..49afc24 100644
--- a/hw/xfree86/common/xf86platformBus.h
+++ b/hw/xfree86/common/xf86platformBus.h
@@ -47,6 +47,11 @@ xf86_remove_platform_device(int dev_index);
extern Bool
xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_str);
+extern int
+xf86platformAddDevice(int index);
+extern void
+xf86platformRemoveDevice(int index);
+
extern _X_EXPORT char *
xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id);
extern _X_EXPORT Bool
diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c
index 9c63ee5..76f5583 100644
--- a/hw/xfree86/os-support/linux/lnx_platform.c
+++ b/hw/xfree86/os-support/linux/lnx_platform.c
@@ -15,6 +15,8 @@
#include "xf86platformBus.h"
#include "xf86Bus.h"
+#include "hotplug.h"
+
static Bool
get_drm_info(struct OdevAttributes *attribs, char *path)
{
@@ -127,4 +129,51 @@ out_free:
config_odev_free_attribute_list(attribs);
}
+void NewGPUDeviceRequest(struct OdevAttributes *attribs)
+{
+ int old_num = xf86_num_platform_devices;
+ int ret;
+ xf86PlatformDeviceProbe(attribs);
+
+ if (old_num == xf86_num_platform_devices)
+ return;
+
+ ret = xf86platformAddDevice(xf86_num_platform_devices-1);
+ if (ret == -1)
+ xf86_remove_platform_device(xf86_num_platform_devices-1);
+
+ ErrorF("xf86: found device %d\n", xf86_num_platform_devices);
+ return;
+}
+
+void DeleteGPUDeviceRequest(struct OdevAttributes *attribs)
+{
+ struct OdevAttribute *attrib;
+ int index;
+ char *syspath = NULL;
+
+ xorg_list_for_each_entry(attrib, &attribs->list, member) {
+ if (attrib->attrib_id == ODEV_ATTRIB_SYSPATH) {
+ syspath = attrib->attrib_name;
+ break;
+ }
+ }
+
+ for (index = 0; index < xf86_num_platform_devices; index++) {
+ char *dspath;
+ dspath = xf86_get_platform_attrib(index, ODEV_ATTRIB_SYSPATH);
+ if (!strcmp(syspath, dspath))
+ break;
+ }
+
+ if (index == xf86_num_platform_devices)
+ goto out;
+
+ ErrorF("xf86: remove device %d %s\n", index, syspath);
+
+ xf86platformRemoveDevice(index);
+out:
+ config_odev_free_attribute_list(attribs);
+}
+
#endif
--
1.7.10.2
More information about the xorg-devel
mailing list