summaryrefslogtreecommitdiff
path: root/src/vdagent/device-info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vdagent/device-info.c')
-rw-r--r--src/vdagent/device-info.c167
1 files changed, 101 insertions, 66 deletions
diff --git a/src/vdagent/device-info.c b/src/vdagent/device-info.c
index 6b0e28f..8cf72c9 100644
--- a/src/vdagent/device-info.c
+++ b/src/vdagent/device-info.c
@@ -388,12 +388,14 @@ static char* find_device_at_pci_address(PciAddress *pci_addr, int *vendor_id, in
return NULL;
}
-// PCI address should be in the following format:
-// pci/$domain/$slot.$fn/$slot.$fn
-bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
- Display *xdisplay,
- XRRScreenResources *xres,
- RROutput *output_id)
+
+/**
+ * Look up DRM info for the device, and retrieve the expected connector name.
+ * This name will later be compared to the monitor names found at the display manager level.
+ */
+int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
+ char *expected_name, size_t name_size,
+ bool has_virtual_zero_display)
{
PciAddress *user_pci_addr = parse_pci_address_from_spice((char*)device_info->device_address);
if (!user_pci_addr) {
@@ -401,7 +403,7 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
"Couldn't parse PCI address '%s'. "
"Address should be the form 'pci/$domain/$slot.$fn/$slot.fn...",
device_info->device_address);
- return false;
+ return -1;
}
int vendor_id = 0;
@@ -412,68 +414,106 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
int drm_fd = open(dev_path, O_RDWR);
if (drm_fd < 0) {
syslog(LOG_WARNING, "Unable to open file %s", dev_path);
- return false;
+ g_free(dev_path);
+ return -1;
}
drmModeResPtr res = drmModeGetResources(drm_fd);
- if (res) {
- // find the drm output that is equal to device_display_id
- if (device_info->device_display_id >= res->count_connectors) {
- syslog(LOG_WARNING,
- "Specified display id %i is higher than the maximum display id "
- "provided by this device (%i)",
- device_info->device_display_id, res->count_connectors - 1);
- close(drm_fd);
- return false;
- }
+ if (res == NULL) {
+ syslog(LOG_WARNING,
+ "Unable to get DRM resources for card %s. "
+ "Falling back to using xrandr output index.",
+ dev_path);
+ close(drm_fd);
+ g_free(dev_path);
+ return 1; // error out - actual handling is deferred to the caller
+ }
- drmModeConnectorPtr conn =
- drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
- drmModeFreeResources(res);
- res = NULL;
+ // no need for dev_path anymore
+ g_free(dev_path);
+
+ // find the drm output that is equal to device_display_id
+ if (device_info->device_display_id >= res->count_connectors) {
+ syslog(LOG_WARNING,
+ "Specified display id %i is higher than the maximum display id "
+ "provided by this device (%i)",
+ device_info->device_display_id, res->count_connectors - 1);
close(drm_fd);
+ return -1;
+ }
- if (conn == NULL) {
- syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
- device_info->device_display_id);
- return false;
- }
+ drmModeConnectorPtr conn =
+ drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
+ drmModeFreeResources(res);
+ res = NULL;
+ close(drm_fd);
- bool decrement_name = false;
- if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
- // Older QXL drivers numbered their outputs starting with
- // 0. This contrasts with most drivers who start numbering
- // outputs with 1. In this case, the expected drm connector
- // name will need to be decremented before comparing to the
- // xrandr output name
- for (int i = 0; i < xres->noutput; ++i) {
- XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
- if (!oinfo) {
- syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
- xres->outputs[i]);
- return false;
- }
- if (strcmp(oinfo->name, "Virtual-0") == 0) {
- decrement_name = true;
- XRRFreeOutputInfo(oinfo);
- break;
- }
- XRRFreeOutputInfo(oinfo);
- }
+ if (conn == NULL) {
+ syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
+ device_info->device_display_id);
+ return -1;
+ }
+
+ bool decrement_name = false;
+
+ if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL
+ && has_virtual_zero_display) {
+ decrement_name = true;
+ }
+
+ // Compare the name of the xrandr output against what we would
+ // expect based on the drm connection type. The xrandr names
+ // are driver-specific, so we need to special-case some
+ // drivers. Most hardware these days uses the 'modesetting'
+ // driver, but the QXL device uses its own driver which has
+ // different naming conventions
+ if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
+ drm_conn_name_qxl(conn, expected_name, name_size, decrement_name);
+ } else {
+ drm_conn_name_modesetting(conn, expected_name, name_size);
+ }
+ drmModeFreeConnector(conn);
+
+ return 0;
+}
+
+// PCI address should be in the following format:
+// pci/$domain/$slot.$fn/$slot.$fn
+bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
+ Display *xdisplay,
+ XRRScreenResources *xres,
+ RROutput *output_id)
+{
+ char expected_name[100];
+ int ret;
+
+ // Older QXL drivers numbered their outputs starting with
+ // 0. This contrasts with most drivers who start numbering
+ // outputs with 1. In this case, the expected drm connector
+ // name will need to be decremented before comparing to the
+ // xrandr output name
+ bool has_virtual_zero_display = false;
+ for (int i = 0; i < xres->noutput; ++i) {
+ XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
+ if (!oinfo) {
+ syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
+ xres->outputs[i]);
+ return false;
}
- // Compare the name of the xrandr output against what we would
- // expect based on the drm connection type. The xrandr names
- // are driver-specific, so we need to special-case some
- // drivers. Most hardware these days uses the 'modesetting'
- // driver, but the QXL device uses its own driver which has
- // different naming conventions
- char expected_name[100];
- if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
- drm_conn_name_qxl(conn, expected_name, sizeof(expected_name), decrement_name);
- } else {
- drm_conn_name_modesetting(conn, expected_name, sizeof(expected_name));
+ if (strcmp(oinfo->name, "Virtual-0") == 0) {
+ has_virtual_zero_display = true;
+ XRRFreeOutputInfo(oinfo);
+ break;
}
+ XRRFreeOutputInfo(oinfo);
+ }
+ ret = get_connector_name_for_device_info(device_info, expected_name, sizeof(expected_name),
+ has_virtual_zero_display);
+ switch (ret) {
+ case -1: // generic error => exit
+ return false;
+ case 0:
// Loop through xrandr outputs and check whether the xrandr
// output name matches the drm connector name
for (int i = 0; i < xres->noutput; ++i) {
@@ -493,13 +533,8 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
}
XRRFreeOutputInfo(oinfo);
}
- drmModeFreeConnector(conn);
- } else {
- close(drm_fd);
- syslog(LOG_WARNING,
- "Unable to get DRM resources for card %s. "
- "Falling back to using xrandr output index.",
- dev_path);
+ break;
+ case 1: // no DRM info found
// This is probably a proprietary driver (e.g. Nvidia) that does
// not provide outputs via drm, so the only thing we can do is just
// assume that it is the only device assigned to X, and use the