summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xf86drmMode.c58
1 files changed, 43 insertions, 15 deletions
diff --git a/xf86drmMode.c b/xf86drmMode.c
index cfdee4a9..f330e6f2 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -410,37 +410,57 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
{
- struct drm_mode_get_connector conn;
+ struct drm_mode_get_connector conn, counts;
drmModeConnectorPtr r = NULL;
+retry:
+ memset(&conn, 0, sizeof(struct drm_mode_get_connector));
conn.connector_id = connector_id;
- conn.connector_type_id = 0;
- conn.connector_type = 0;
- conn.count_modes = 0;
- conn.modes_ptr = 0;
- conn.count_props = 0;
- conn.props_ptr = 0;
- conn.prop_values_ptr = 0;
- conn.count_encoders = 0;
- conn.encoders_ptr = 0;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
return 0;
+ counts = conn;
+
if (conn.count_props) {
conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
+ if (!conn.props_ptr)
+ goto err_allocs;
conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
+ if (!conn.prop_values_ptr)
+ goto err_allocs;
}
- if (conn.count_modes)
+ if (conn.count_modes) {
conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
+ if (!conn.modes_ptr)
+ goto err_allocs;
+ }
- if (conn.count_encoders)
+ if (conn.count_encoders) {
conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
+ if (!conn.encoders_ptr)
+ goto err_allocs;
+ }
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
goto err_allocs;
+ /* The number of available connectors and etc may have changed with a
+ * hotplug event in between the ioctls, in which case the field is
+ * silently ignored by the kernel.
+ */
+ if (counts.count_props < conn.count_props ||
+ counts.count_modes < conn.count_modes ||
+ counts.count_encoders < conn.count_encoders) {
+ drmFree(U642VOID(conn.props_ptr));
+ drmFree(U642VOID(conn.prop_values_ptr));
+ drmFree(U642VOID(conn.modes_ptr));
+ drmFree(U642VOID(conn.encoders_ptr));
+
+ goto retry;
+ }
+
if(!(r = drmMalloc(sizeof(*r)))) {
goto err_allocs;
}
@@ -453,7 +473,6 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
/* convert subpixel from kernel to userspace */
r->subpixel = conn.subpixel + 1;
r->count_modes = conn.count_modes;
- /* TODO we should test if these alloc & cpy fails. */
r->count_props = conn.count_props;
r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
@@ -463,8 +482,17 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
r->connector_type = conn.connector_type;
r->connector_type_id = conn.connector_type_id;
- if (!r->props || !r->prop_values || !r->modes || !r->encoders)
- goto err_allocs;
+ if ((r->count_props && !r->props) ||
+ (r->count_props && !r->prop_values) ||
+ (r->count_modes && !r->modes) ||
+ (r->count_encoders && !r->encoders)) {
+ drmFree(r->props);
+ drmFree(r->prop_values);
+ drmFree(r->modes);
+ drmFree(r->encoders);
+ drmFree(r);
+ r = 0;
+ }
err_allocs:
drmFree(U642VOID(conn.prop_values_ptr));