diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 071f44b2a..1d1f87c74 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -272,6 +272,22 @@ xf86PlatformMatchDriver(XF86MatchedDrivers *md) } } +void xf86PlatformScanPciDev(void) +{ + int i; + + if (!xf86scanpci()) + return; + + xf86Msg(X_CONFIG, "Scanning the platform PCI devices\n"); + for (i = 0; i < xf86_num_platform_devices; i++) { + char *busid = xf86_platform_odev_attributes(i)->busid; + + if (strncmp(busid, "pci:", 4) == 0) + platform_find_pci_info(&xf86_platform_devices[i], busid); + } +} + int xf86platformProbe(void) { @@ -613,31 +629,58 @@ xf86platformAddGPUDevices(DriverPtr drvp) return foundScreen; } +const char * +xf86PlatformFindHotplugDriver(int dev_index) +{ + XF86ConfOutputClassPtr cl; + const char *hp_driver = NULL; + struct xf86_platform_device *dev = &xf86_platform_devices[dev_index]; + + for (cl = xf86configptr->conf_outputclass_lst; cl; cl = cl->list.next) { + if (!OutputClassMatches(cl, dev) || !cl->option_lst) + continue; + + hp_driver = xf86FindOptionValue(cl->option_lst, "HotplugDriver"); + if (hp_driver) + xf86MarkOptionUsed(cl->option_lst); + } + + /* Return the first driver from the match list */ + xf86Msg(X_INFO, "matching hotplug-driver is %s\n", + hp_driver ? hp_driver : "none"); + return hp_driver; +} + int -xf86platformAddDevice(int index) +xf86platformAddDevice(const char *driver_name, int index) { int i, old_screens, scr_index, scrnum; DriverPtr drvp = NULL; screenLayoutPtr layout; - static const char *hotplug_driver_name = "modesetting"; if (!xf86Info.autoAddGPU) return -1; - /* force load the driver for now */ - xf86LoadOneModule(hotplug_driver_name, NULL); + /* Load modesetting driver if no driver given, or driver open failed */ + if (!driver_name || !xf86LoadOneModule(driver_name, NULL)) { + driver_name = "modesetting"; + xf86LoadOneModule(driver_name, NULL); + } for (i = 0; i < xf86NumDrivers; i++) { if (!xf86DriverList[i]) continue; - if (!strcmp(xf86DriverList[i]->driverName, hotplug_driver_name)) { + if (!strcmp(xf86DriverList[i]->driverName, driver_name)) { drvp = xf86DriverList[i]; break; } } - if (i == xf86NumDrivers) + + if (i == xf86NumDrivers) { + ErrorF("can't find driver %s for hotplugged device\n", driver_name); return -1; + } old_screens = xf86NumGPUScreens; doPlatformProbe(&xf86_platform_devices[index], drvp, NULL, diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h index 1e75e6352..9979106a1 100644 --- a/hw/xfree86/common/xf86platformBus.h +++ b/hw/xfree86/common/xf86platformBus.h @@ -44,6 +44,8 @@ int xf86platformProbe(void); int xf86platformProbeDev(DriverPtr drvp); int xf86platformAddGPUDevices(DriverPtr drvp); void xf86MergeOutputClassOptions(int entityIndex, void **options); +void xf86PlatformScanPciDev(void); +const char *xf86PlatformFindHotplugDriver(int dev_index); extern int xf86_num_platform_devices; extern struct xf86_platform_device *xf86_platform_devices; @@ -56,7 +58,7 @@ extern Bool xf86_get_platform_device_unowned(int index); extern int -xf86platformAddDevice(int index); +xf86platformAddDevice(const char *driver_name, int index); extern void xf86platformRemoveDevice(int index); diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man index ac88d7e7a..01b47247e 100644 --- a/hw/xfree86/man/xorg.conf.man +++ b/hw/xfree86/man/xorg.conf.man @@ -1296,7 +1296,20 @@ This option specifies that the matched device should be treated as the primary GPU, replacing the selection of the GPU used as output by the firmware. If multiple output devices match an OutputClass section with the PrimaryGPU option set, the first one enumerated becomes the primary GPU. -.PP +.TP 7 +.BI "Option \*qHotplugDriver\*q \*q" driver \*q +This option specifies that the matched driver should be used to handle a +hot-plugged GPU device. +The module specified by +.I driver +will be loaded during setup of the GPU device. +If loading of this module fails or there is no driver by that name, the +modesetting driver will be used, which is the default behavior. +If multiple output devices match an +.B OutputClass +section with the +.B HotplugDriver +option, the first one enumerated becomes the hotplug driver. A .B OutputClass Section may contain diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c index 8a6be97aa..90013573c 100644 --- a/hw/xfree86/os-support/linux/lnx_platform.c +++ b/hw/xfree86/os-support/linux/lnx_platform.c @@ -125,7 +125,7 @@ xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs) xf86_remove_platform_device(index); return; } - ret = xf86platformAddDevice(index); + ret = xf86platformAddDevice(xf86PlatformFindHotplugDriver(index), index); if (ret == -1) xf86_remove_platform_device(index); } @@ -173,6 +173,8 @@ void NewGPUDeviceRequest(struct OdevAttributes *attribs) { int old_num = xf86_num_platform_devices; int ret; + const char *driver_name; + xf86PlatformDeviceProbe(attribs); if (old_num == xf86_num_platform_devices) @@ -181,7 +183,11 @@ void NewGPUDeviceRequest(struct OdevAttributes *attribs) if (xf86_get_platform_device_unowned(xf86_num_platform_devices - 1) == TRUE) return; - ret = xf86platformAddDevice(xf86_num_platform_devices-1); + /* Scan and update PCI devices before adding new platform device */ + xf86PlatformScanPciDev(); + driver_name = xf86PlatformFindHotplugDriver(xf86_num_platform_devices - 1); + + ret = xf86platformAddDevice(driver_name, xf86_num_platform_devices-1); if (ret == -1) xf86_remove_platform_device(xf86_num_platform_devices-1);