diff options
| -rw-r--r-- | drivers/gpu/drm/drm_connector.c | 44 | ||||
| -rw-r--r-- | include/drm/drm_modes.h | 13 |
2 files changed, 50 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index dfc8ca1e9413..9b9ba5d5ec0c 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c | |||
| @@ -1531,8 +1531,10 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne | |||
| 1531 | return connector->encoder; | 1531 | return connector->encoder; |
| 1532 | } | 1532 | } |
| 1533 | 1533 | ||
| 1534 | static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, | 1534 | static bool |
| 1535 | const struct drm_file *file_priv) | 1535 | drm_mode_expose_to_userspace(const struct drm_display_mode *mode, |
| 1536 | const struct list_head *export_list, | ||
| 1537 | const struct drm_file *file_priv) | ||
| 1536 | { | 1538 | { |
| 1537 | /* | 1539 | /* |
| 1538 | * If user-space hasn't configured the driver to expose the stereo 3D | 1540 | * If user-space hasn't configured the driver to expose the stereo 3D |
| @@ -1540,6 +1542,23 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, | |||
| 1540 | */ | 1542 | */ |
| 1541 | if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) | 1543 | if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) |
| 1542 | return false; | 1544 | return false; |
| 1545 | /* | ||
| 1546 | * If user-space hasn't configured the driver to expose the modes | ||
| 1547 | * with aspect-ratio, don't expose them. However if such a mode | ||
| 1548 | * is unique, let it be exposed, but reset the aspect-ratio flags | ||
| 1549 | * while preparing the list of user-modes. | ||
| 1550 | */ | ||
| 1551 | if (!file_priv->aspect_ratio_allowed) { | ||
| 1552 | struct drm_display_mode *mode_itr; | ||
| 1553 | |||
| 1554 | list_for_each_entry(mode_itr, export_list, export_head) | ||
| 1555 | if (drm_mode_match(mode_itr, mode, | ||
| 1556 | DRM_MODE_MATCH_TIMINGS | | ||
| 1557 | DRM_MODE_MATCH_CLOCK | | ||
| 1558 | DRM_MODE_MATCH_FLAGS | | ||
| 1559 | DRM_MODE_MATCH_3D_FLAGS)) | ||
| 1560 | return false; | ||
| 1561 | } | ||
| 1543 | 1562 | ||
| 1544 | return true; | 1563 | return true; |
| 1545 | } | 1564 | } |
| @@ -1559,6 +1578,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 1559 | struct drm_mode_modeinfo u_mode; | 1578 | struct drm_mode_modeinfo u_mode; |
| 1560 | struct drm_mode_modeinfo __user *mode_ptr; | 1579 | struct drm_mode_modeinfo __user *mode_ptr; |
| 1561 | uint32_t __user *encoder_ptr; | 1580 | uint32_t __user *encoder_ptr; |
| 1581 | LIST_HEAD(export_list); | ||
| 1562 | 1582 | ||
| 1563 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1583 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 1564 | return -EINVAL; | 1584 | return -EINVAL; |
| @@ -1607,21 +1627,31 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 1607 | 1627 | ||
| 1608 | /* delayed so we get modes regardless of pre-fill_modes state */ | 1628 | /* delayed so we get modes regardless of pre-fill_modes state */ |
| 1609 | list_for_each_entry(mode, &connector->modes, head) | 1629 | list_for_each_entry(mode, &connector->modes, head) |
| 1610 | if (drm_mode_expose_to_userspace(mode, file_priv)) | 1630 | if (drm_mode_expose_to_userspace(mode, &export_list, |
| 1631 | file_priv)) { | ||
| 1632 | list_add_tail(&mode->export_head, &export_list); | ||
| 1611 | mode_count++; | 1633 | mode_count++; |
| 1634 | } | ||
| 1612 | 1635 | ||
| 1613 | /* | 1636 | /* |
| 1614 | * This ioctl is called twice, once to determine how much space is | 1637 | * This ioctl is called twice, once to determine how much space is |
| 1615 | * needed, and the 2nd time to fill it. | 1638 | * needed, and the 2nd time to fill it. |
| 1639 | * The modes that need to be exposed to the user are maintained in the | ||
| 1640 | * 'export_list'. When the ioctl is called first time to determine the, | ||
| 1641 | * space, the export_list gets filled, to find the no.of modes. In the | ||
| 1642 | * 2nd time, the user modes are filled, one by one from the export_list. | ||
| 1616 | */ | 1643 | */ |
| 1617 | if ((out_resp->count_modes >= mode_count) && mode_count) { | 1644 | if ((out_resp->count_modes >= mode_count) && mode_count) { |
| 1618 | copied = 0; | 1645 | copied = 0; |
| 1619 | mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; | 1646 | mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; |
| 1620 | list_for_each_entry(mode, &connector->modes, head) { | 1647 | list_for_each_entry(mode, &export_list, export_head) { |
| 1621 | if (!drm_mode_expose_to_userspace(mode, file_priv)) | ||
| 1622 | continue; | ||
| 1623 | |||
| 1624 | drm_mode_convert_to_umode(&u_mode, mode); | 1648 | drm_mode_convert_to_umode(&u_mode, mode); |
| 1649 | /* | ||
| 1650 | * Reset aspect ratio flags of user-mode, if modes with | ||
| 1651 | * aspect-ratio are not supported. | ||
| 1652 | */ | ||
| 1653 | if (!file_priv->aspect_ratio_allowed) | ||
| 1654 | u_mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; | ||
| 1625 | if (copy_to_user(mode_ptr + copied, | 1655 | if (copy_to_user(mode_ptr + copied, |
| 1626 | &u_mode, sizeof(u_mode))) { | 1656 | &u_mode, sizeof(u_mode))) { |
| 1627 | ret = -EFAULT; | 1657 | ret = -EFAULT; |
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 2f78b7ee4824..b159fe07fcf9 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h | |||
| @@ -411,6 +411,19 @@ struct drm_display_mode { | |||
| 411 | * Field for setting the HDMI picture aspect ratio of a mode. | 411 | * Field for setting the HDMI picture aspect ratio of a mode. |
| 412 | */ | 412 | */ |
| 413 | enum hdmi_picture_aspect picture_aspect_ratio; | 413 | enum hdmi_picture_aspect picture_aspect_ratio; |
| 414 | |||
| 415 | /** | ||
| 416 | * @export_head: | ||
| 417 | * | ||
| 418 | * struct list_head for modes to be exposed to the userspace. | ||
| 419 | * This is to maintain a list of exposed modes while preparing | ||
| 420 | * user-mode's list in drm_mode_getconnector ioctl. The purpose of this | ||
| 421 | * list_head only lies in the ioctl function, and is not expected to be | ||
| 422 | * used outside the function. | ||
| 423 | * Once used, the stale pointers are not reset, but left as it is, to | ||
| 424 | * avoid overhead of protecting it by mode_config.mutex. | ||
| 425 | */ | ||
| 426 | struct list_head export_head; | ||
| 414 | }; | 427 | }; |
| 415 | 428 | ||
| 416 | /** | 429 | /** |
