diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-08-29 04:27:55 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-08-29 09:37:34 -0400 |
commit | 59e71ee746a37fe077b73cecf189de1d27efd6eb (patch) | |
tree | 4c31aab686d6d4c3cca5410b8a6d5b42ead9c840 | |
parent | ec5e304747241823435b160d3eabf1295c06d2e3 (diff) |
drm: Extract drm_property.[hc]
This just contains the base property classes and all the code to
handle blobs. I think for any kind of standardized/shared properties
it's better to have separate files - this is fairly big already as-is.
v2: resurrect misplaced hunk (Daniel Stone)
Cc: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20160829082757.17913-7-daniel.vetter@ffwll.ch
-rw-r--r-- | Documentation/gpu/drm-kms.rst | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 926 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_internal.h | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_property.c | 953 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 88 | ||||
-rw-r--r-- | include/drm/drm_property.h | 120 |
7 files changed, 1102 insertions, 1028 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index b164472f2157..e07a2667ab61 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst | |||
@@ -389,6 +389,15 @@ connector and plane objects by calling the | |||
389 | pointer to the target object, a pointer to the previously created | 389 | pointer to the target object, a pointer to the previously created |
390 | property and an initial instance value. | 390 | property and an initial instance value. |
391 | 391 | ||
392 | Property Types and Blob Property Support | ||
393 | ---------------------------------------- | ||
394 | |||
395 | .. kernel-doc:: include/drm/drm_property.h | ||
396 | :internal: | ||
397 | |||
398 | .. kernel-doc:: drivers/gpu/drm/drm_property.c | ||
399 | :export: | ||
400 | |||
392 | Blending and Z-Position properties | 401 | Blending and Z-Position properties |
393 | ---------------------------------- | 402 | ---------------------------------- |
394 | 403 | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 59979f3f3648..12a966ec7298 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ | 14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ | 15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ |
16 | drm_framebuffer.o drm_connector.o drm_blend.o \ | 16 | drm_framebuffer.o drm_connector.o drm_blend.o \ |
17 | drm_encoder.o drm_mode_object.o | 17 | drm_encoder.o drm_mode_object.o drm_property.o |
18 | 18 | ||
19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9ff58e6b51c4..b95c48acfa5b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -1671,932 +1671,6 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev, | |||
1671 | return drm_mode_cursor_common(dev, req, file_priv); | 1671 | return drm_mode_cursor_common(dev, req, file_priv); |
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | static bool drm_property_type_valid(struct drm_property *property) | ||
1675 | { | ||
1676 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
1677 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
1678 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
1679 | } | ||
1680 | |||
1681 | /** | ||
1682 | * drm_property_create - create a new property type | ||
1683 | * @dev: drm device | ||
1684 | * @flags: flags specifying the property type | ||
1685 | * @name: name of the property | ||
1686 | * @num_values: number of pre-defined values | ||
1687 | * | ||
1688 | * This creates a new generic drm property which can then be attached to a drm | ||
1689 | * object with drm_object_attach_property. The returned property object must be | ||
1690 | * freed with drm_property_destroy. | ||
1691 | * | ||
1692 | * Note that the DRM core keeps a per-device list of properties and that, if | ||
1693 | * drm_mode_config_cleanup() is called, it will destroy all properties created | ||
1694 | * by the driver. | ||
1695 | * | ||
1696 | * Returns: | ||
1697 | * A pointer to the newly created property on success, NULL on failure. | ||
1698 | */ | ||
1699 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
1700 | const char *name, int num_values) | ||
1701 | { | ||
1702 | struct drm_property *property = NULL; | ||
1703 | int ret; | ||
1704 | |||
1705 | property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); | ||
1706 | if (!property) | ||
1707 | return NULL; | ||
1708 | |||
1709 | property->dev = dev; | ||
1710 | |||
1711 | if (num_values) { | ||
1712 | property->values = kcalloc(num_values, sizeof(uint64_t), | ||
1713 | GFP_KERNEL); | ||
1714 | if (!property->values) | ||
1715 | goto fail; | ||
1716 | } | ||
1717 | |||
1718 | ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); | ||
1719 | if (ret) | ||
1720 | goto fail; | ||
1721 | |||
1722 | property->flags = flags; | ||
1723 | property->num_values = num_values; | ||
1724 | INIT_LIST_HEAD(&property->enum_list); | ||
1725 | |||
1726 | if (name) { | ||
1727 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | ||
1728 | property->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
1729 | } | ||
1730 | |||
1731 | list_add_tail(&property->head, &dev->mode_config.property_list); | ||
1732 | |||
1733 | WARN_ON(!drm_property_type_valid(property)); | ||
1734 | |||
1735 | return property; | ||
1736 | fail: | ||
1737 | kfree(property->values); | ||
1738 | kfree(property); | ||
1739 | return NULL; | ||
1740 | } | ||
1741 | EXPORT_SYMBOL(drm_property_create); | ||
1742 | |||
1743 | /** | ||
1744 | * drm_property_create_enum - create a new enumeration property type | ||
1745 | * @dev: drm device | ||
1746 | * @flags: flags specifying the property type | ||
1747 | * @name: name of the property | ||
1748 | * @props: enumeration lists with property values | ||
1749 | * @num_values: number of pre-defined values | ||
1750 | * | ||
1751 | * This creates a new generic drm property which can then be attached to a drm | ||
1752 | * object with drm_object_attach_property. The returned property object must be | ||
1753 | * freed with drm_property_destroy. | ||
1754 | * | ||
1755 | * Userspace is only allowed to set one of the predefined values for enumeration | ||
1756 | * properties. | ||
1757 | * | ||
1758 | * Returns: | ||
1759 | * A pointer to the newly created property on success, NULL on failure. | ||
1760 | */ | ||
1761 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
1762 | const char *name, | ||
1763 | const struct drm_prop_enum_list *props, | ||
1764 | int num_values) | ||
1765 | { | ||
1766 | struct drm_property *property; | ||
1767 | int i, ret; | ||
1768 | |||
1769 | flags |= DRM_MODE_PROP_ENUM; | ||
1770 | |||
1771 | property = drm_property_create(dev, flags, name, num_values); | ||
1772 | if (!property) | ||
1773 | return NULL; | ||
1774 | |||
1775 | for (i = 0; i < num_values; i++) { | ||
1776 | ret = drm_property_add_enum(property, i, | ||
1777 | props[i].type, | ||
1778 | props[i].name); | ||
1779 | if (ret) { | ||
1780 | drm_property_destroy(dev, property); | ||
1781 | return NULL; | ||
1782 | } | ||
1783 | } | ||
1784 | |||
1785 | return property; | ||
1786 | } | ||
1787 | EXPORT_SYMBOL(drm_property_create_enum); | ||
1788 | |||
1789 | /** | ||
1790 | * drm_property_create_bitmask - create a new bitmask property type | ||
1791 | * @dev: drm device | ||
1792 | * @flags: flags specifying the property type | ||
1793 | * @name: name of the property | ||
1794 | * @props: enumeration lists with property bitflags | ||
1795 | * @num_props: size of the @props array | ||
1796 | * @supported_bits: bitmask of all supported enumeration values | ||
1797 | * | ||
1798 | * This creates a new bitmask drm property which can then be attached to a drm | ||
1799 | * object with drm_object_attach_property. The returned property object must be | ||
1800 | * freed with drm_property_destroy. | ||
1801 | * | ||
1802 | * Compared to plain enumeration properties userspace is allowed to set any | ||
1803 | * or'ed together combination of the predefined property bitflag values | ||
1804 | * | ||
1805 | * Returns: | ||
1806 | * A pointer to the newly created property on success, NULL on failure. | ||
1807 | */ | ||
1808 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
1809 | int flags, const char *name, | ||
1810 | const struct drm_prop_enum_list *props, | ||
1811 | int num_props, | ||
1812 | uint64_t supported_bits) | ||
1813 | { | ||
1814 | struct drm_property *property; | ||
1815 | int i, ret, index = 0; | ||
1816 | int num_values = hweight64(supported_bits); | ||
1817 | |||
1818 | flags |= DRM_MODE_PROP_BITMASK; | ||
1819 | |||
1820 | property = drm_property_create(dev, flags, name, num_values); | ||
1821 | if (!property) | ||
1822 | return NULL; | ||
1823 | for (i = 0; i < num_props; i++) { | ||
1824 | if (!(supported_bits & (1ULL << props[i].type))) | ||
1825 | continue; | ||
1826 | |||
1827 | if (WARN_ON(index >= num_values)) { | ||
1828 | drm_property_destroy(dev, property); | ||
1829 | return NULL; | ||
1830 | } | ||
1831 | |||
1832 | ret = drm_property_add_enum(property, index++, | ||
1833 | props[i].type, | ||
1834 | props[i].name); | ||
1835 | if (ret) { | ||
1836 | drm_property_destroy(dev, property); | ||
1837 | return NULL; | ||
1838 | } | ||
1839 | } | ||
1840 | |||
1841 | return property; | ||
1842 | } | ||
1843 | EXPORT_SYMBOL(drm_property_create_bitmask); | ||
1844 | |||
1845 | static struct drm_property *property_create_range(struct drm_device *dev, | ||
1846 | int flags, const char *name, | ||
1847 | uint64_t min, uint64_t max) | ||
1848 | { | ||
1849 | struct drm_property *property; | ||
1850 | |||
1851 | property = drm_property_create(dev, flags, name, 2); | ||
1852 | if (!property) | ||
1853 | return NULL; | ||
1854 | |||
1855 | property->values[0] = min; | ||
1856 | property->values[1] = max; | ||
1857 | |||
1858 | return property; | ||
1859 | } | ||
1860 | |||
1861 | /** | ||
1862 | * drm_property_create_range - create a new unsigned ranged property type | ||
1863 | * @dev: drm device | ||
1864 | * @flags: flags specifying the property type | ||
1865 | * @name: name of the property | ||
1866 | * @min: minimum value of the property | ||
1867 | * @max: maximum value of the property | ||
1868 | * | ||
1869 | * This creates a new generic drm property which can then be attached to a drm | ||
1870 | * object with drm_object_attach_property. The returned property object must be | ||
1871 | * freed with drm_property_destroy. | ||
1872 | * | ||
1873 | * Userspace is allowed to set any unsigned integer value in the (min, max) | ||
1874 | * range inclusive. | ||
1875 | * | ||
1876 | * Returns: | ||
1877 | * A pointer to the newly created property on success, NULL on failure. | ||
1878 | */ | ||
1879 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
1880 | const char *name, | ||
1881 | uint64_t min, uint64_t max) | ||
1882 | { | ||
1883 | return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, | ||
1884 | name, min, max); | ||
1885 | } | ||
1886 | EXPORT_SYMBOL(drm_property_create_range); | ||
1887 | |||
1888 | /** | ||
1889 | * drm_property_create_signed_range - create a new signed ranged property type | ||
1890 | * @dev: drm device | ||
1891 | * @flags: flags specifying the property type | ||
1892 | * @name: name of the property | ||
1893 | * @min: minimum value of the property | ||
1894 | * @max: maximum value of the property | ||
1895 | * | ||
1896 | * This creates a new generic drm property which can then be attached to a drm | ||
1897 | * object with drm_object_attach_property. The returned property object must be | ||
1898 | * freed with drm_property_destroy. | ||
1899 | * | ||
1900 | * Userspace is allowed to set any signed integer value in the (min, max) | ||
1901 | * range inclusive. | ||
1902 | * | ||
1903 | * Returns: | ||
1904 | * A pointer to the newly created property on success, NULL on failure. | ||
1905 | */ | ||
1906 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
1907 | int flags, const char *name, | ||
1908 | int64_t min, int64_t max) | ||
1909 | { | ||
1910 | return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, | ||
1911 | name, I642U64(min), I642U64(max)); | ||
1912 | } | ||
1913 | EXPORT_SYMBOL(drm_property_create_signed_range); | ||
1914 | |||
1915 | /** | ||
1916 | * drm_property_create_object - create a new object property type | ||
1917 | * @dev: drm device | ||
1918 | * @flags: flags specifying the property type | ||
1919 | * @name: name of the property | ||
1920 | * @type: object type from DRM_MODE_OBJECT_* defines | ||
1921 | * | ||
1922 | * This creates a new generic drm property which can then be attached to a drm | ||
1923 | * object with drm_object_attach_property. The returned property object must be | ||
1924 | * freed with drm_property_destroy. | ||
1925 | * | ||
1926 | * Userspace is only allowed to set this to any property value of the given | ||
1927 | * @type. Only useful for atomic properties, which is enforced. | ||
1928 | * | ||
1929 | * Returns: | ||
1930 | * A pointer to the newly created property on success, NULL on failure. | ||
1931 | */ | ||
1932 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
1933 | int flags, const char *name, uint32_t type) | ||
1934 | { | ||
1935 | struct drm_property *property; | ||
1936 | |||
1937 | flags |= DRM_MODE_PROP_OBJECT; | ||
1938 | |||
1939 | if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) | ||
1940 | return NULL; | ||
1941 | |||
1942 | property = drm_property_create(dev, flags, name, 1); | ||
1943 | if (!property) | ||
1944 | return NULL; | ||
1945 | |||
1946 | property->values[0] = type; | ||
1947 | |||
1948 | return property; | ||
1949 | } | ||
1950 | EXPORT_SYMBOL(drm_property_create_object); | ||
1951 | |||
1952 | /** | ||
1953 | * drm_property_create_bool - create a new boolean property type | ||
1954 | * @dev: drm device | ||
1955 | * @flags: flags specifying the property type | ||
1956 | * @name: name of the property | ||
1957 | * | ||
1958 | * This creates a new generic drm property which can then be attached to a drm | ||
1959 | * object with drm_object_attach_property. The returned property object must be | ||
1960 | * freed with drm_property_destroy. | ||
1961 | * | ||
1962 | * This is implemented as a ranged property with only {0, 1} as valid values. | ||
1963 | * | ||
1964 | * Returns: | ||
1965 | * A pointer to the newly created property on success, NULL on failure. | ||
1966 | */ | ||
1967 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
1968 | const char *name) | ||
1969 | { | ||
1970 | return drm_property_create_range(dev, flags, name, 0, 1); | ||
1971 | } | ||
1972 | EXPORT_SYMBOL(drm_property_create_bool); | ||
1973 | |||
1974 | /** | ||
1975 | * drm_property_add_enum - add a possible value to an enumeration property | ||
1976 | * @property: enumeration property to change | ||
1977 | * @index: index of the new enumeration | ||
1978 | * @value: value of the new enumeration | ||
1979 | * @name: symbolic name of the new enumeration | ||
1980 | * | ||
1981 | * This functions adds enumerations to a property. | ||
1982 | * | ||
1983 | * It's use is deprecated, drivers should use one of the more specific helpers | ||
1984 | * to directly create the property with all enumerations already attached. | ||
1985 | * | ||
1986 | * Returns: | ||
1987 | * Zero on success, error code on failure. | ||
1988 | */ | ||
1989 | int drm_property_add_enum(struct drm_property *property, int index, | ||
1990 | uint64_t value, const char *name) | ||
1991 | { | ||
1992 | struct drm_property_enum *prop_enum; | ||
1993 | |||
1994 | if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
1995 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) | ||
1996 | return -EINVAL; | ||
1997 | |||
1998 | /* | ||
1999 | * Bitmask enum properties have the additional constraint of values | ||
2000 | * from 0 to 63 | ||
2001 | */ | ||
2002 | if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && | ||
2003 | (value > 63)) | ||
2004 | return -EINVAL; | ||
2005 | |||
2006 | if (!list_empty(&property->enum_list)) { | ||
2007 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
2008 | if (prop_enum->value == value) { | ||
2009 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
2010 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
2011 | return 0; | ||
2012 | } | ||
2013 | } | ||
2014 | } | ||
2015 | |||
2016 | prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); | ||
2017 | if (!prop_enum) | ||
2018 | return -ENOMEM; | ||
2019 | |||
2020 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
2021 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
2022 | prop_enum->value = value; | ||
2023 | |||
2024 | property->values[index] = value; | ||
2025 | list_add_tail(&prop_enum->head, &property->enum_list); | ||
2026 | return 0; | ||
2027 | } | ||
2028 | EXPORT_SYMBOL(drm_property_add_enum); | ||
2029 | |||
2030 | /** | ||
2031 | * drm_property_destroy - destroy a drm property | ||
2032 | * @dev: drm device | ||
2033 | * @property: property to destry | ||
2034 | * | ||
2035 | * This function frees a property including any attached resources like | ||
2036 | * enumeration values. | ||
2037 | */ | ||
2038 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | ||
2039 | { | ||
2040 | struct drm_property_enum *prop_enum, *pt; | ||
2041 | |||
2042 | list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { | ||
2043 | list_del(&prop_enum->head); | ||
2044 | kfree(prop_enum); | ||
2045 | } | ||
2046 | |||
2047 | if (property->num_values) | ||
2048 | kfree(property->values); | ||
2049 | drm_mode_object_unregister(dev, &property->base); | ||
2050 | list_del(&property->head); | ||
2051 | kfree(property); | ||
2052 | } | ||
2053 | EXPORT_SYMBOL(drm_property_destroy); | ||
2054 | |||
2055 | /** | ||
2056 | * drm_mode_getproperty_ioctl - get the property metadata | ||
2057 | * @dev: DRM device | ||
2058 | * @data: ioctl data | ||
2059 | * @file_priv: DRM file info | ||
2060 | * | ||
2061 | * This function retrieves the metadata for a given property, like the different | ||
2062 | * possible values for an enum property or the limits for a range property. | ||
2063 | * | ||
2064 | * Blob properties are special | ||
2065 | * | ||
2066 | * Called by the user via ioctl. | ||
2067 | * | ||
2068 | * Returns: | ||
2069 | * Zero on success, negative errno on failure. | ||
2070 | */ | ||
2071 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
2072 | void *data, struct drm_file *file_priv) | ||
2073 | { | ||
2074 | struct drm_mode_get_property *out_resp = data; | ||
2075 | struct drm_property *property; | ||
2076 | int enum_count = 0; | ||
2077 | int value_count = 0; | ||
2078 | int ret = 0, i; | ||
2079 | int copied; | ||
2080 | struct drm_property_enum *prop_enum; | ||
2081 | struct drm_mode_property_enum __user *enum_ptr; | ||
2082 | uint64_t __user *values_ptr; | ||
2083 | |||
2084 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2085 | return -EINVAL; | ||
2086 | |||
2087 | drm_modeset_lock_all(dev); | ||
2088 | property = drm_property_find(dev, out_resp->prop_id); | ||
2089 | if (!property) { | ||
2090 | ret = -ENOENT; | ||
2091 | goto done; | ||
2092 | } | ||
2093 | |||
2094 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
2095 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
2096 | list_for_each_entry(prop_enum, &property->enum_list, head) | ||
2097 | enum_count++; | ||
2098 | } | ||
2099 | |||
2100 | value_count = property->num_values; | ||
2101 | |||
2102 | strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); | ||
2103 | out_resp->name[DRM_PROP_NAME_LEN-1] = 0; | ||
2104 | out_resp->flags = property->flags; | ||
2105 | |||
2106 | if ((out_resp->count_values >= value_count) && value_count) { | ||
2107 | values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; | ||
2108 | for (i = 0; i < value_count; i++) { | ||
2109 | if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { | ||
2110 | ret = -EFAULT; | ||
2111 | goto done; | ||
2112 | } | ||
2113 | } | ||
2114 | } | ||
2115 | out_resp->count_values = value_count; | ||
2116 | |||
2117 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
2118 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
2119 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | ||
2120 | copied = 0; | ||
2121 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; | ||
2122 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
2123 | |||
2124 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | ||
2125 | ret = -EFAULT; | ||
2126 | goto done; | ||
2127 | } | ||
2128 | |||
2129 | if (copy_to_user(&enum_ptr[copied].name, | ||
2130 | &prop_enum->name, DRM_PROP_NAME_LEN)) { | ||
2131 | ret = -EFAULT; | ||
2132 | goto done; | ||
2133 | } | ||
2134 | copied++; | ||
2135 | } | ||
2136 | } | ||
2137 | out_resp->count_enum_blobs = enum_count; | ||
2138 | } | ||
2139 | |||
2140 | /* | ||
2141 | * NOTE: The idea seems to have been to use this to read all the blob | ||
2142 | * property values. But nothing ever added them to the corresponding | ||
2143 | * list, userspace always used the special-purpose get_blob ioctl to | ||
2144 | * read the value for a blob property. It also doesn't make a lot of | ||
2145 | * sense to return values here when everything else is just metadata for | ||
2146 | * the property itself. | ||
2147 | */ | ||
2148 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
2149 | out_resp->count_enum_blobs = 0; | ||
2150 | done: | ||
2151 | drm_modeset_unlock_all(dev); | ||
2152 | return ret; | ||
2153 | } | ||
2154 | |||
2155 | static void drm_property_free_blob(struct kref *kref) | ||
2156 | { | ||
2157 | struct drm_property_blob *blob = | ||
2158 | container_of(kref, struct drm_property_blob, base.refcount); | ||
2159 | |||
2160 | mutex_lock(&blob->dev->mode_config.blob_lock); | ||
2161 | list_del(&blob->head_global); | ||
2162 | mutex_unlock(&blob->dev->mode_config.blob_lock); | ||
2163 | |||
2164 | drm_mode_object_unregister(blob->dev, &blob->base); | ||
2165 | |||
2166 | kfree(blob); | ||
2167 | } | ||
2168 | |||
2169 | /** | ||
2170 | * drm_property_create_blob - Create new blob property | ||
2171 | * | ||
2172 | * Creates a new blob property for a specified DRM device, optionally | ||
2173 | * copying data. | ||
2174 | * | ||
2175 | * @dev: DRM device to create property for | ||
2176 | * @length: Length to allocate for blob data | ||
2177 | * @data: If specified, copies data into blob | ||
2178 | * | ||
2179 | * Returns: | ||
2180 | * New blob property with a single reference on success, or an ERR_PTR | ||
2181 | * value on failure. | ||
2182 | */ | ||
2183 | struct drm_property_blob * | ||
2184 | drm_property_create_blob(struct drm_device *dev, size_t length, | ||
2185 | const void *data) | ||
2186 | { | ||
2187 | struct drm_property_blob *blob; | ||
2188 | int ret; | ||
2189 | |||
2190 | if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) | ||
2191 | return ERR_PTR(-EINVAL); | ||
2192 | |||
2193 | blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); | ||
2194 | if (!blob) | ||
2195 | return ERR_PTR(-ENOMEM); | ||
2196 | |||
2197 | /* This must be explicitly initialised, so we can safely call list_del | ||
2198 | * on it in the removal handler, even if it isn't in a file list. */ | ||
2199 | INIT_LIST_HEAD(&blob->head_file); | ||
2200 | blob->length = length; | ||
2201 | blob->dev = dev; | ||
2202 | |||
2203 | if (data) | ||
2204 | memcpy(blob->data, data, length); | ||
2205 | |||
2206 | ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, | ||
2207 | true, drm_property_free_blob); | ||
2208 | if (ret) { | ||
2209 | kfree(blob); | ||
2210 | return ERR_PTR(-EINVAL); | ||
2211 | } | ||
2212 | |||
2213 | mutex_lock(&dev->mode_config.blob_lock); | ||
2214 | list_add_tail(&blob->head_global, | ||
2215 | &dev->mode_config.property_blob_list); | ||
2216 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2217 | |||
2218 | return blob; | ||
2219 | } | ||
2220 | EXPORT_SYMBOL(drm_property_create_blob); | ||
2221 | |||
2222 | /** | ||
2223 | * drm_property_unreference_blob - Unreference a blob property | ||
2224 | * | ||
2225 | * Drop a reference on a blob property. May free the object. | ||
2226 | * | ||
2227 | * @blob: Pointer to blob property | ||
2228 | */ | ||
2229 | void drm_property_unreference_blob(struct drm_property_blob *blob) | ||
2230 | { | ||
2231 | if (!blob) | ||
2232 | return; | ||
2233 | |||
2234 | drm_mode_object_unreference(&blob->base); | ||
2235 | } | ||
2236 | EXPORT_SYMBOL(drm_property_unreference_blob); | ||
2237 | |||
2238 | /** | ||
2239 | * drm_property_destroy_user_blobs - destroy all blobs created by this client | ||
2240 | * @dev: DRM device | ||
2241 | * @file_priv: destroy all blobs owned by this file handle | ||
2242 | */ | ||
2243 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
2244 | struct drm_file *file_priv) | ||
2245 | { | ||
2246 | struct drm_property_blob *blob, *bt; | ||
2247 | |||
2248 | /* | ||
2249 | * When the file gets released that means no one else can access the | ||
2250 | * blob list any more, so no need to grab dev->blob_lock. | ||
2251 | */ | ||
2252 | list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { | ||
2253 | list_del_init(&blob->head_file); | ||
2254 | drm_property_unreference_blob(blob); | ||
2255 | } | ||
2256 | } | ||
2257 | |||
2258 | /** | ||
2259 | * drm_property_reference_blob - Take a reference on an existing property | ||
2260 | * | ||
2261 | * Take a new reference on an existing blob property. | ||
2262 | * | ||
2263 | * @blob: Pointer to blob property | ||
2264 | */ | ||
2265 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) | ||
2266 | { | ||
2267 | drm_mode_object_reference(&blob->base); | ||
2268 | return blob; | ||
2269 | } | ||
2270 | EXPORT_SYMBOL(drm_property_reference_blob); | ||
2271 | |||
2272 | /** | ||
2273 | * drm_property_lookup_blob - look up a blob property and take a reference | ||
2274 | * @dev: drm device | ||
2275 | * @id: id of the blob property | ||
2276 | * | ||
2277 | * If successful, this takes an additional reference to the blob property. | ||
2278 | * callers need to make sure to eventually unreference the returned property | ||
2279 | * again, using @drm_property_unreference_blob. | ||
2280 | */ | ||
2281 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
2282 | uint32_t id) | ||
2283 | { | ||
2284 | struct drm_mode_object *obj; | ||
2285 | struct drm_property_blob *blob = NULL; | ||
2286 | |||
2287 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); | ||
2288 | if (obj) | ||
2289 | blob = obj_to_blob(obj); | ||
2290 | return blob; | ||
2291 | } | ||
2292 | EXPORT_SYMBOL(drm_property_lookup_blob); | ||
2293 | |||
2294 | /** | ||
2295 | * drm_property_replace_global_blob - atomically replace existing blob property | ||
2296 | * @dev: drm device | ||
2297 | * @replace: location of blob property pointer to be replaced | ||
2298 | * @length: length of data for new blob, or 0 for no data | ||
2299 | * @data: content for new blob, or NULL for no data | ||
2300 | * @obj_holds_id: optional object for property holding blob ID | ||
2301 | * @prop_holds_id: optional property holding blob ID | ||
2302 | * @return 0 on success or error on failure | ||
2303 | * | ||
2304 | * This function will atomically replace a global property in the blob list, | ||
2305 | * optionally updating a property which holds the ID of that property. It is | ||
2306 | * guaranteed to be atomic: no caller will be allowed to see intermediate | ||
2307 | * results, and either the entire operation will succeed and clean up the | ||
2308 | * previous property, or it will fail and the state will be unchanged. | ||
2309 | * | ||
2310 | * If length is 0 or data is NULL, no new blob will be created, and the holding | ||
2311 | * property, if specified, will be set to 0. | ||
2312 | * | ||
2313 | * Access to the replace pointer is assumed to be protected by the caller, e.g. | ||
2314 | * by holding the relevant modesetting object lock for its parent. | ||
2315 | * | ||
2316 | * For example, a drm_connector has a 'PATH' property, which contains the ID | ||
2317 | * of a blob property with the value of the MST path information. Calling this | ||
2318 | * function with replace pointing to the connector's path_blob_ptr, length and | ||
2319 | * data set for the new path information, obj_holds_id set to the connector's | ||
2320 | * base object, and prop_holds_id set to the path property name, will perform | ||
2321 | * a completely atomic update. The access to path_blob_ptr is protected by the | ||
2322 | * caller holding a lock on the connector. | ||
2323 | */ | ||
2324 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
2325 | struct drm_property_blob **replace, | ||
2326 | size_t length, | ||
2327 | const void *data, | ||
2328 | struct drm_mode_object *obj_holds_id, | ||
2329 | struct drm_property *prop_holds_id) | ||
2330 | { | ||
2331 | struct drm_property_blob *new_blob = NULL; | ||
2332 | struct drm_property_blob *old_blob = NULL; | ||
2333 | int ret; | ||
2334 | |||
2335 | WARN_ON(replace == NULL); | ||
2336 | |||
2337 | old_blob = *replace; | ||
2338 | |||
2339 | if (length && data) { | ||
2340 | new_blob = drm_property_create_blob(dev, length, data); | ||
2341 | if (IS_ERR(new_blob)) | ||
2342 | return PTR_ERR(new_blob); | ||
2343 | } | ||
2344 | |||
2345 | /* This does not need to be synchronised with blob_lock, as the | ||
2346 | * get_properties ioctl locks all modesetting objects, and | ||
2347 | * obj_holds_id must be locked before calling here, so we cannot | ||
2348 | * have its value out of sync with the list membership modified | ||
2349 | * below under blob_lock. */ | ||
2350 | if (obj_holds_id) { | ||
2351 | ret = drm_object_property_set_value(obj_holds_id, | ||
2352 | prop_holds_id, | ||
2353 | new_blob ? | ||
2354 | new_blob->base.id : 0); | ||
2355 | if (ret != 0) | ||
2356 | goto err_created; | ||
2357 | } | ||
2358 | |||
2359 | drm_property_unreference_blob(old_blob); | ||
2360 | *replace = new_blob; | ||
2361 | |||
2362 | return 0; | ||
2363 | |||
2364 | err_created: | ||
2365 | drm_property_unreference_blob(new_blob); | ||
2366 | return ret; | ||
2367 | } | ||
2368 | EXPORT_SYMBOL(drm_property_replace_global_blob); | ||
2369 | |||
2370 | /** | ||
2371 | * drm_mode_getblob_ioctl - get the contents of a blob property value | ||
2372 | * @dev: DRM device | ||
2373 | * @data: ioctl data | ||
2374 | * @file_priv: DRM file info | ||
2375 | * | ||
2376 | * This function retrieves the contents of a blob property. The value stored in | ||
2377 | * an object's blob property is just a normal modeset object id. | ||
2378 | * | ||
2379 | * Called by the user via ioctl. | ||
2380 | * | ||
2381 | * Returns: | ||
2382 | * Zero on success, negative errno on failure. | ||
2383 | */ | ||
2384 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
2385 | void *data, struct drm_file *file_priv) | ||
2386 | { | ||
2387 | struct drm_mode_get_blob *out_resp = data; | ||
2388 | struct drm_property_blob *blob; | ||
2389 | int ret = 0; | ||
2390 | void __user *blob_ptr; | ||
2391 | |||
2392 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2393 | return -EINVAL; | ||
2394 | |||
2395 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
2396 | if (!blob) | ||
2397 | return -ENOENT; | ||
2398 | |||
2399 | if (out_resp->length == blob->length) { | ||
2400 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
2401 | if (copy_to_user(blob_ptr, blob->data, blob->length)) { | ||
2402 | ret = -EFAULT; | ||
2403 | goto unref; | ||
2404 | } | ||
2405 | } | ||
2406 | out_resp->length = blob->length; | ||
2407 | unref: | ||
2408 | drm_property_unreference_blob(blob); | ||
2409 | |||
2410 | return ret; | ||
2411 | } | ||
2412 | |||
2413 | /** | ||
2414 | * drm_mode_createblob_ioctl - create a new blob property | ||
2415 | * @dev: DRM device | ||
2416 | * @data: ioctl data | ||
2417 | * @file_priv: DRM file info | ||
2418 | * | ||
2419 | * This function creates a new blob property with user-defined values. In order | ||
2420 | * to give us sensible validation and checking when creating, rather than at | ||
2421 | * every potential use, we also require a type to be provided upfront. | ||
2422 | * | ||
2423 | * Called by the user via ioctl. | ||
2424 | * | ||
2425 | * Returns: | ||
2426 | * Zero on success, negative errno on failure. | ||
2427 | */ | ||
2428 | int drm_mode_createblob_ioctl(struct drm_device *dev, | ||
2429 | void *data, struct drm_file *file_priv) | ||
2430 | { | ||
2431 | struct drm_mode_create_blob *out_resp = data; | ||
2432 | struct drm_property_blob *blob; | ||
2433 | void __user *blob_ptr; | ||
2434 | int ret = 0; | ||
2435 | |||
2436 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2437 | return -EINVAL; | ||
2438 | |||
2439 | blob = drm_property_create_blob(dev, out_resp->length, NULL); | ||
2440 | if (IS_ERR(blob)) | ||
2441 | return PTR_ERR(blob); | ||
2442 | |||
2443 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
2444 | if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { | ||
2445 | ret = -EFAULT; | ||
2446 | goto out_blob; | ||
2447 | } | ||
2448 | |||
2449 | /* Dropping the lock between create_blob and our access here is safe | ||
2450 | * as only the same file_priv can remove the blob; at this point, it is | ||
2451 | * not associated with any file_priv. */ | ||
2452 | mutex_lock(&dev->mode_config.blob_lock); | ||
2453 | out_resp->blob_id = blob->base.id; | ||
2454 | list_add_tail(&blob->head_file, &file_priv->blobs); | ||
2455 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2456 | |||
2457 | return 0; | ||
2458 | |||
2459 | out_blob: | ||
2460 | drm_property_unreference_blob(blob); | ||
2461 | return ret; | ||
2462 | } | ||
2463 | |||
2464 | /** | ||
2465 | * drm_mode_destroyblob_ioctl - destroy a user blob property | ||
2466 | * @dev: DRM device | ||
2467 | * @data: ioctl data | ||
2468 | * @file_priv: DRM file info | ||
2469 | * | ||
2470 | * Destroy an existing user-defined blob property. | ||
2471 | * | ||
2472 | * Called by the user via ioctl. | ||
2473 | * | ||
2474 | * Returns: | ||
2475 | * Zero on success, negative errno on failure. | ||
2476 | */ | ||
2477 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | ||
2478 | void *data, struct drm_file *file_priv) | ||
2479 | { | ||
2480 | struct drm_mode_destroy_blob *out_resp = data; | ||
2481 | struct drm_property_blob *blob = NULL, *bt; | ||
2482 | bool found = false; | ||
2483 | int ret = 0; | ||
2484 | |||
2485 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2486 | return -EINVAL; | ||
2487 | |||
2488 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
2489 | if (!blob) | ||
2490 | return -ENOENT; | ||
2491 | |||
2492 | mutex_lock(&dev->mode_config.blob_lock); | ||
2493 | /* Ensure the property was actually created by this user. */ | ||
2494 | list_for_each_entry(bt, &file_priv->blobs, head_file) { | ||
2495 | if (bt == blob) { | ||
2496 | found = true; | ||
2497 | break; | ||
2498 | } | ||
2499 | } | ||
2500 | |||
2501 | if (!found) { | ||
2502 | ret = -EPERM; | ||
2503 | goto err; | ||
2504 | } | ||
2505 | |||
2506 | /* We must drop head_file here, because we may not be the last | ||
2507 | * reference on the blob. */ | ||
2508 | list_del_init(&blob->head_file); | ||
2509 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2510 | |||
2511 | /* One reference from lookup, and one from the filp. */ | ||
2512 | drm_property_unreference_blob(blob); | ||
2513 | drm_property_unreference_blob(blob); | ||
2514 | |||
2515 | return 0; | ||
2516 | |||
2517 | err: | ||
2518 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2519 | drm_property_unreference_blob(blob); | ||
2520 | |||
2521 | return ret; | ||
2522 | } | ||
2523 | |||
2524 | /* Some properties could refer to dynamic refcnt'd objects, or things that | ||
2525 | * need special locking to handle lifetime issues (ie. to ensure the prop | ||
2526 | * value doesn't become invalid part way through the property update due to | ||
2527 | * race). The value returned by reference via 'obj' should be passed back | ||
2528 | * to drm_property_change_valid_put() after the property is set (and the | ||
2529 | * object to which the property is attached has a chance to take it's own | ||
2530 | * reference). | ||
2531 | */ | ||
2532 | bool drm_property_change_valid_get(struct drm_property *property, | ||
2533 | uint64_t value, struct drm_mode_object **ref) | ||
2534 | { | ||
2535 | int i; | ||
2536 | |||
2537 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | ||
2538 | return false; | ||
2539 | |||
2540 | *ref = NULL; | ||
2541 | |||
2542 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | ||
2543 | if (value < property->values[0] || value > property->values[1]) | ||
2544 | return false; | ||
2545 | return true; | ||
2546 | } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { | ||
2547 | int64_t svalue = U642I64(value); | ||
2548 | |||
2549 | if (svalue < U642I64(property->values[0]) || | ||
2550 | svalue > U642I64(property->values[1])) | ||
2551 | return false; | ||
2552 | return true; | ||
2553 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
2554 | uint64_t valid_mask = 0; | ||
2555 | |||
2556 | for (i = 0; i < property->num_values; i++) | ||
2557 | valid_mask |= (1ULL << property->values[i]); | ||
2558 | return !(value & ~valid_mask); | ||
2559 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { | ||
2560 | struct drm_property_blob *blob; | ||
2561 | |||
2562 | if (value == 0) | ||
2563 | return true; | ||
2564 | |||
2565 | blob = drm_property_lookup_blob(property->dev, value); | ||
2566 | if (blob) { | ||
2567 | *ref = &blob->base; | ||
2568 | return true; | ||
2569 | } else { | ||
2570 | return false; | ||
2571 | } | ||
2572 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
2573 | /* a zero value for an object property translates to null: */ | ||
2574 | if (value == 0) | ||
2575 | return true; | ||
2576 | |||
2577 | *ref = __drm_mode_object_find(property->dev, value, | ||
2578 | property->values[0]); | ||
2579 | return *ref != NULL; | ||
2580 | } | ||
2581 | |||
2582 | for (i = 0; i < property->num_values; i++) | ||
2583 | if (property->values[i] == value) | ||
2584 | return true; | ||
2585 | return false; | ||
2586 | } | ||
2587 | |||
2588 | void drm_property_change_valid_put(struct drm_property *property, | ||
2589 | struct drm_mode_object *ref) | ||
2590 | { | ||
2591 | if (!ref) | ||
2592 | return; | ||
2593 | |||
2594 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
2595 | drm_mode_object_unreference(ref); | ||
2596 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
2597 | drm_property_unreference_blob(obj_to_blob(ref)); | ||
2598 | } | ||
2599 | |||
2600 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | 1674 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
2601 | struct drm_property *property, | 1675 | struct drm_property *property, |
2602 | uint64_t value) | 1676 | uint64_t value) |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 2eb1d941ea70..a3622644bccf 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -36,11 +36,6 @@ | |||
36 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | 36 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
37 | struct drm_property *property, | 37 | struct drm_property *property, |
38 | uint64_t value); | 38 | uint64_t value); |
39 | bool drm_property_change_valid_get(struct drm_property *property, | ||
40 | uint64_t value, | ||
41 | struct drm_mode_object **ref); | ||
42 | void drm_property_change_valid_put(struct drm_property *property, | ||
43 | struct drm_mode_object *ref); | ||
44 | int drm_plane_check_pixel_format(const struct drm_plane *plane, | 39 | int drm_plane_check_pixel_format(const struct drm_plane *plane, |
45 | u32 format); | 40 | u32 format); |
46 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, | 41 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, |
@@ -49,8 +44,6 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, | |||
49 | const struct drm_framebuffer *fb); | 44 | const struct drm_framebuffer *fb); |
50 | 45 | ||
51 | void drm_fb_release(struct drm_file *file_priv); | 46 | void drm_fb_release(struct drm_file *file_priv); |
52 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
53 | struct drm_file *file_priv); | ||
54 | 47 | ||
55 | /* dumb buffer support IOCTLs */ | 48 | /* dumb buffer support IOCTLs */ |
56 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, | 49 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, |
@@ -77,6 +70,24 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
77 | void *data, struct drm_file *file_priv); | 70 | void *data, struct drm_file *file_priv); |
78 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | 71 | int drm_mode_cursor2_ioctl(struct drm_device *dev, |
79 | void *data, struct drm_file *file_priv); | 72 | void *data, struct drm_file *file_priv); |
73 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
74 | void *data, struct drm_file *file_priv); | ||
75 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
76 | void *data, struct drm_file *file_priv); | ||
77 | |||
78 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
79 | void *data, struct drm_file *file_priv); | ||
80 | |||
81 | /* drm_property.c */ | ||
82 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
83 | struct drm_file *file_priv); | ||
84 | bool drm_property_change_valid_get(struct drm_property *property, | ||
85 | uint64_t value, | ||
86 | struct drm_mode_object **ref); | ||
87 | void drm_property_change_valid_put(struct drm_property *property, | ||
88 | struct drm_mode_object *ref); | ||
89 | |||
90 | /* IOCTL */ | ||
80 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | 91 | int drm_mode_getproperty_ioctl(struct drm_device *dev, |
81 | void *data, struct drm_file *file_priv); | 92 | void *data, struct drm_file *file_priv); |
82 | int drm_mode_getblob_ioctl(struct drm_device *dev, | 93 | int drm_mode_getblob_ioctl(struct drm_device *dev, |
@@ -85,13 +96,6 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, | |||
85 | void *data, struct drm_file *file_priv); | 96 | void *data, struct drm_file *file_priv); |
86 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | 97 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, |
87 | void *data, struct drm_file *file_priv); | 98 | void *data, struct drm_file *file_priv); |
88 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
89 | void *data, struct drm_file *file_priv); | ||
90 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
91 | void *data, struct drm_file *file_priv); | ||
92 | |||
93 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
94 | void *data, struct drm_file *file_priv); | ||
95 | 99 | ||
96 | /* drm_mode_object.c */ | 100 | /* drm_mode_object.c */ |
97 | int drm_mode_object_get_reg(struct drm_device *dev, | 101 | int drm_mode_object_get_reg(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c new file mode 100644 index 000000000000..162cc9032ae5 --- /dev/null +++ b/drivers/gpu/drm/drm_property.c | |||
@@ -0,0 +1,953 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <linux/export.h> | ||
24 | #include <drm/drmP.h> | ||
25 | #include <drm/drm_property.h> | ||
26 | |||
27 | #include "drm_crtc_internal.h" | ||
28 | |||
29 | static bool drm_property_type_valid(struct drm_property *property) | ||
30 | { | ||
31 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
32 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
33 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * drm_property_create - create a new property type | ||
38 | * @dev: drm device | ||
39 | * @flags: flags specifying the property type | ||
40 | * @name: name of the property | ||
41 | * @num_values: number of pre-defined values | ||
42 | * | ||
43 | * This creates a new generic drm property which can then be attached to a drm | ||
44 | * object with drm_object_attach_property. The returned property object must be | ||
45 | * freed with drm_property_destroy. | ||
46 | * | ||
47 | * Note that the DRM core keeps a per-device list of properties and that, if | ||
48 | * drm_mode_config_cleanup() is called, it will destroy all properties created | ||
49 | * by the driver. | ||
50 | * | ||
51 | * Returns: | ||
52 | * A pointer to the newly created property on success, NULL on failure. | ||
53 | */ | ||
54 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
55 | const char *name, int num_values) | ||
56 | { | ||
57 | struct drm_property *property = NULL; | ||
58 | int ret; | ||
59 | |||
60 | property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); | ||
61 | if (!property) | ||
62 | return NULL; | ||
63 | |||
64 | property->dev = dev; | ||
65 | |||
66 | if (num_values) { | ||
67 | property->values = kcalloc(num_values, sizeof(uint64_t), | ||
68 | GFP_KERNEL); | ||
69 | if (!property->values) | ||
70 | goto fail; | ||
71 | } | ||
72 | |||
73 | ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); | ||
74 | if (ret) | ||
75 | goto fail; | ||
76 | |||
77 | property->flags = flags; | ||
78 | property->num_values = num_values; | ||
79 | INIT_LIST_HEAD(&property->enum_list); | ||
80 | |||
81 | if (name) { | ||
82 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | ||
83 | property->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
84 | } | ||
85 | |||
86 | list_add_tail(&property->head, &dev->mode_config.property_list); | ||
87 | |||
88 | WARN_ON(!drm_property_type_valid(property)); | ||
89 | |||
90 | return property; | ||
91 | fail: | ||
92 | kfree(property->values); | ||
93 | kfree(property); | ||
94 | return NULL; | ||
95 | } | ||
96 | EXPORT_SYMBOL(drm_property_create); | ||
97 | |||
98 | /** | ||
99 | * drm_property_create_enum - create a new enumeration property type | ||
100 | * @dev: drm device | ||
101 | * @flags: flags specifying the property type | ||
102 | * @name: name of the property | ||
103 | * @props: enumeration lists with property values | ||
104 | * @num_values: number of pre-defined values | ||
105 | * | ||
106 | * This creates a new generic drm property which can then be attached to a drm | ||
107 | * object with drm_object_attach_property. The returned property object must be | ||
108 | * freed with drm_property_destroy. | ||
109 | * | ||
110 | * Userspace is only allowed to set one of the predefined values for enumeration | ||
111 | * properties. | ||
112 | * | ||
113 | * Returns: | ||
114 | * A pointer to the newly created property on success, NULL on failure. | ||
115 | */ | ||
116 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
117 | const char *name, | ||
118 | const struct drm_prop_enum_list *props, | ||
119 | int num_values) | ||
120 | { | ||
121 | struct drm_property *property; | ||
122 | int i, ret; | ||
123 | |||
124 | flags |= DRM_MODE_PROP_ENUM; | ||
125 | |||
126 | property = drm_property_create(dev, flags, name, num_values); | ||
127 | if (!property) | ||
128 | return NULL; | ||
129 | |||
130 | for (i = 0; i < num_values; i++) { | ||
131 | ret = drm_property_add_enum(property, i, | ||
132 | props[i].type, | ||
133 | props[i].name); | ||
134 | if (ret) { | ||
135 | drm_property_destroy(dev, property); | ||
136 | return NULL; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | return property; | ||
141 | } | ||
142 | EXPORT_SYMBOL(drm_property_create_enum); | ||
143 | |||
144 | /** | ||
145 | * drm_property_create_bitmask - create a new bitmask property type | ||
146 | * @dev: drm device | ||
147 | * @flags: flags specifying the property type | ||
148 | * @name: name of the property | ||
149 | * @props: enumeration lists with property bitflags | ||
150 | * @num_props: size of the @props array | ||
151 | * @supported_bits: bitmask of all supported enumeration values | ||
152 | * | ||
153 | * This creates a new bitmask drm property which can then be attached to a drm | ||
154 | * object with drm_object_attach_property. The returned property object must be | ||
155 | * freed with drm_property_destroy. | ||
156 | * | ||
157 | * Compared to plain enumeration properties userspace is allowed to set any | ||
158 | * or'ed together combination of the predefined property bitflag values | ||
159 | * | ||
160 | * Returns: | ||
161 | * A pointer to the newly created property on success, NULL on failure. | ||
162 | */ | ||
163 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
164 | int flags, const char *name, | ||
165 | const struct drm_prop_enum_list *props, | ||
166 | int num_props, | ||
167 | uint64_t supported_bits) | ||
168 | { | ||
169 | struct drm_property *property; | ||
170 | int i, ret, index = 0; | ||
171 | int num_values = hweight64(supported_bits); | ||
172 | |||
173 | flags |= DRM_MODE_PROP_BITMASK; | ||
174 | |||
175 | property = drm_property_create(dev, flags, name, num_values); | ||
176 | if (!property) | ||
177 | return NULL; | ||
178 | for (i = 0; i < num_props; i++) { | ||
179 | if (!(supported_bits & (1ULL << props[i].type))) | ||
180 | continue; | ||
181 | |||
182 | if (WARN_ON(index >= num_values)) { | ||
183 | drm_property_destroy(dev, property); | ||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | ret = drm_property_add_enum(property, index++, | ||
188 | props[i].type, | ||
189 | props[i].name); | ||
190 | if (ret) { | ||
191 | drm_property_destroy(dev, property); | ||
192 | return NULL; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | return property; | ||
197 | } | ||
198 | EXPORT_SYMBOL(drm_property_create_bitmask); | ||
199 | |||
200 | static struct drm_property *property_create_range(struct drm_device *dev, | ||
201 | int flags, const char *name, | ||
202 | uint64_t min, uint64_t max) | ||
203 | { | ||
204 | struct drm_property *property; | ||
205 | |||
206 | property = drm_property_create(dev, flags, name, 2); | ||
207 | if (!property) | ||
208 | return NULL; | ||
209 | |||
210 | property->values[0] = min; | ||
211 | property->values[1] = max; | ||
212 | |||
213 | return property; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * drm_property_create_range - create a new unsigned ranged property type | ||
218 | * @dev: drm device | ||
219 | * @flags: flags specifying the property type | ||
220 | * @name: name of the property | ||
221 | * @min: minimum value of the property | ||
222 | * @max: maximum value of the property | ||
223 | * | ||
224 | * This creates a new generic drm property which can then be attached to a drm | ||
225 | * object with drm_object_attach_property. The returned property object must be | ||
226 | * freed with drm_property_destroy. | ||
227 | * | ||
228 | * Userspace is allowed to set any unsigned integer value in the (min, max) | ||
229 | * range inclusive. | ||
230 | * | ||
231 | * Returns: | ||
232 | * A pointer to the newly created property on success, NULL on failure. | ||
233 | */ | ||
234 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
235 | const char *name, | ||
236 | uint64_t min, uint64_t max) | ||
237 | { | ||
238 | return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, | ||
239 | name, min, max); | ||
240 | } | ||
241 | EXPORT_SYMBOL(drm_property_create_range); | ||
242 | |||
243 | /** | ||
244 | * drm_property_create_signed_range - create a new signed ranged property type | ||
245 | * @dev: drm device | ||
246 | * @flags: flags specifying the property type | ||
247 | * @name: name of the property | ||
248 | * @min: minimum value of the property | ||
249 | * @max: maximum value of the property | ||
250 | * | ||
251 | * This creates a new generic drm property which can then be attached to a drm | ||
252 | * object with drm_object_attach_property. The returned property object must be | ||
253 | * freed with drm_property_destroy. | ||
254 | * | ||
255 | * Userspace is allowed to set any signed integer value in the (min, max) | ||
256 | * range inclusive. | ||
257 | * | ||
258 | * Returns: | ||
259 | * A pointer to the newly created property on success, NULL on failure. | ||
260 | */ | ||
261 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
262 | int flags, const char *name, | ||
263 | int64_t min, int64_t max) | ||
264 | { | ||
265 | return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, | ||
266 | name, I642U64(min), I642U64(max)); | ||
267 | } | ||
268 | EXPORT_SYMBOL(drm_property_create_signed_range); | ||
269 | |||
270 | /** | ||
271 | * drm_property_create_object - create a new object property type | ||
272 | * @dev: drm device | ||
273 | * @flags: flags specifying the property type | ||
274 | * @name: name of the property | ||
275 | * @type: object type from DRM_MODE_OBJECT_* defines | ||
276 | * | ||
277 | * This creates a new generic drm property which can then be attached to a drm | ||
278 | * object with drm_object_attach_property. The returned property object must be | ||
279 | * freed with drm_property_destroy. | ||
280 | * | ||
281 | * Userspace is only allowed to set this to any property value of the given | ||
282 | * @type. Only useful for atomic properties, which is enforced. | ||
283 | * | ||
284 | * Returns: | ||
285 | * A pointer to the newly created property on success, NULL on failure. | ||
286 | */ | ||
287 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
288 | int flags, const char *name, uint32_t type) | ||
289 | { | ||
290 | struct drm_property *property; | ||
291 | |||
292 | flags |= DRM_MODE_PROP_OBJECT; | ||
293 | |||
294 | if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) | ||
295 | return NULL; | ||
296 | |||
297 | property = drm_property_create(dev, flags, name, 1); | ||
298 | if (!property) | ||
299 | return NULL; | ||
300 | |||
301 | property->values[0] = type; | ||
302 | |||
303 | return property; | ||
304 | } | ||
305 | EXPORT_SYMBOL(drm_property_create_object); | ||
306 | |||
307 | /** | ||
308 | * drm_property_create_bool - create a new boolean property type | ||
309 | * @dev: drm device | ||
310 | * @flags: flags specifying the property type | ||
311 | * @name: name of the property | ||
312 | * | ||
313 | * This creates a new generic drm property which can then be attached to a drm | ||
314 | * object with drm_object_attach_property. The returned property object must be | ||
315 | * freed with drm_property_destroy. | ||
316 | * | ||
317 | * This is implemented as a ranged property with only {0, 1} as valid values. | ||
318 | * | ||
319 | * Returns: | ||
320 | * A pointer to the newly created property on success, NULL on failure. | ||
321 | */ | ||
322 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
323 | const char *name) | ||
324 | { | ||
325 | return drm_property_create_range(dev, flags, name, 0, 1); | ||
326 | } | ||
327 | EXPORT_SYMBOL(drm_property_create_bool); | ||
328 | |||
329 | /** | ||
330 | * drm_property_add_enum - add a possible value to an enumeration property | ||
331 | * @property: enumeration property to change | ||
332 | * @index: index of the new enumeration | ||
333 | * @value: value of the new enumeration | ||
334 | * @name: symbolic name of the new enumeration | ||
335 | * | ||
336 | * This functions adds enumerations to a property. | ||
337 | * | ||
338 | * It's use is deprecated, drivers should use one of the more specific helpers | ||
339 | * to directly create the property with all enumerations already attached. | ||
340 | * | ||
341 | * Returns: | ||
342 | * Zero on success, error code on failure. | ||
343 | */ | ||
344 | int drm_property_add_enum(struct drm_property *property, int index, | ||
345 | uint64_t value, const char *name) | ||
346 | { | ||
347 | struct drm_property_enum *prop_enum; | ||
348 | |||
349 | if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
350 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) | ||
351 | return -EINVAL; | ||
352 | |||
353 | /* | ||
354 | * Bitmask enum properties have the additional constraint of values | ||
355 | * from 0 to 63 | ||
356 | */ | ||
357 | if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && | ||
358 | (value > 63)) | ||
359 | return -EINVAL; | ||
360 | |||
361 | if (!list_empty(&property->enum_list)) { | ||
362 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
363 | if (prop_enum->value == value) { | ||
364 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
365 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
366 | return 0; | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); | ||
372 | if (!prop_enum) | ||
373 | return -ENOMEM; | ||
374 | |||
375 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
376 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
377 | prop_enum->value = value; | ||
378 | |||
379 | property->values[index] = value; | ||
380 | list_add_tail(&prop_enum->head, &property->enum_list); | ||
381 | return 0; | ||
382 | } | ||
383 | EXPORT_SYMBOL(drm_property_add_enum); | ||
384 | |||
385 | /** | ||
386 | * drm_property_destroy - destroy a drm property | ||
387 | * @dev: drm device | ||
388 | * @property: property to destry | ||
389 | * | ||
390 | * This function frees a property including any attached resources like | ||
391 | * enumeration values. | ||
392 | */ | ||
393 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | ||
394 | { | ||
395 | struct drm_property_enum *prop_enum, *pt; | ||
396 | |||
397 | list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { | ||
398 | list_del(&prop_enum->head); | ||
399 | kfree(prop_enum); | ||
400 | } | ||
401 | |||
402 | if (property->num_values) | ||
403 | kfree(property->values); | ||
404 | drm_mode_object_unregister(dev, &property->base); | ||
405 | list_del(&property->head); | ||
406 | kfree(property); | ||
407 | } | ||
408 | EXPORT_SYMBOL(drm_property_destroy); | ||
409 | |||
410 | /** | ||
411 | * drm_mode_getproperty_ioctl - get the property metadata | ||
412 | * @dev: DRM device | ||
413 | * @data: ioctl data | ||
414 | * @file_priv: DRM file info | ||
415 | * | ||
416 | * This function retrieves the metadata for a given property, like the different | ||
417 | * possible values for an enum property or the limits for a range property. | ||
418 | * | ||
419 | * Blob properties are special | ||
420 | * | ||
421 | * Called by the user via ioctl. | ||
422 | * | ||
423 | * Returns: | ||
424 | * Zero on success, negative errno on failure. | ||
425 | */ | ||
426 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
427 | void *data, struct drm_file *file_priv) | ||
428 | { | ||
429 | struct drm_mode_get_property *out_resp = data; | ||
430 | struct drm_property *property; | ||
431 | int enum_count = 0; | ||
432 | int value_count = 0; | ||
433 | int ret = 0, i; | ||
434 | int copied; | ||
435 | struct drm_property_enum *prop_enum; | ||
436 | struct drm_mode_property_enum __user *enum_ptr; | ||
437 | uint64_t __user *values_ptr; | ||
438 | |||
439 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
440 | return -EINVAL; | ||
441 | |||
442 | drm_modeset_lock_all(dev); | ||
443 | property = drm_property_find(dev, out_resp->prop_id); | ||
444 | if (!property) { | ||
445 | ret = -ENOENT; | ||
446 | goto done; | ||
447 | } | ||
448 | |||
449 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
450 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
451 | list_for_each_entry(prop_enum, &property->enum_list, head) | ||
452 | enum_count++; | ||
453 | } | ||
454 | |||
455 | value_count = property->num_values; | ||
456 | |||
457 | strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); | ||
458 | out_resp->name[DRM_PROP_NAME_LEN-1] = 0; | ||
459 | out_resp->flags = property->flags; | ||
460 | |||
461 | if ((out_resp->count_values >= value_count) && value_count) { | ||
462 | values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; | ||
463 | for (i = 0; i < value_count; i++) { | ||
464 | if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { | ||
465 | ret = -EFAULT; | ||
466 | goto done; | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | out_resp->count_values = value_count; | ||
471 | |||
472 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
473 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
474 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | ||
475 | copied = 0; | ||
476 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; | ||
477 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
478 | |||
479 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | ||
480 | ret = -EFAULT; | ||
481 | goto done; | ||
482 | } | ||
483 | |||
484 | if (copy_to_user(&enum_ptr[copied].name, | ||
485 | &prop_enum->name, DRM_PROP_NAME_LEN)) { | ||
486 | ret = -EFAULT; | ||
487 | goto done; | ||
488 | } | ||
489 | copied++; | ||
490 | } | ||
491 | } | ||
492 | out_resp->count_enum_blobs = enum_count; | ||
493 | } | ||
494 | |||
495 | /* | ||
496 | * NOTE: The idea seems to have been to use this to read all the blob | ||
497 | * property values. But nothing ever added them to the corresponding | ||
498 | * list, userspace always used the special-purpose get_blob ioctl to | ||
499 | * read the value for a blob property. It also doesn't make a lot of | ||
500 | * sense to return values here when everything else is just metadata for | ||
501 | * the property itself. | ||
502 | */ | ||
503 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
504 | out_resp->count_enum_blobs = 0; | ||
505 | done: | ||
506 | drm_modeset_unlock_all(dev); | ||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | static void drm_property_free_blob(struct kref *kref) | ||
511 | { | ||
512 | struct drm_property_blob *blob = | ||
513 | container_of(kref, struct drm_property_blob, base.refcount); | ||
514 | |||
515 | mutex_lock(&blob->dev->mode_config.blob_lock); | ||
516 | list_del(&blob->head_global); | ||
517 | mutex_unlock(&blob->dev->mode_config.blob_lock); | ||
518 | |||
519 | drm_mode_object_unregister(blob->dev, &blob->base); | ||
520 | |||
521 | kfree(blob); | ||
522 | } | ||
523 | |||
524 | /** | ||
525 | * drm_property_create_blob - Create new blob property | ||
526 | * | ||
527 | * Creates a new blob property for a specified DRM device, optionally | ||
528 | * copying data. | ||
529 | * | ||
530 | * @dev: DRM device to create property for | ||
531 | * @length: Length to allocate for blob data | ||
532 | * @data: If specified, copies data into blob | ||
533 | * | ||
534 | * Returns: | ||
535 | * New blob property with a single reference on success, or an ERR_PTR | ||
536 | * value on failure. | ||
537 | */ | ||
538 | struct drm_property_blob * | ||
539 | drm_property_create_blob(struct drm_device *dev, size_t length, | ||
540 | const void *data) | ||
541 | { | ||
542 | struct drm_property_blob *blob; | ||
543 | int ret; | ||
544 | |||
545 | if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) | ||
546 | return ERR_PTR(-EINVAL); | ||
547 | |||
548 | blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); | ||
549 | if (!blob) | ||
550 | return ERR_PTR(-ENOMEM); | ||
551 | |||
552 | /* This must be explicitly initialised, so we can safely call list_del | ||
553 | * on it in the removal handler, even if it isn't in a file list. */ | ||
554 | INIT_LIST_HEAD(&blob->head_file); | ||
555 | blob->length = length; | ||
556 | blob->dev = dev; | ||
557 | |||
558 | if (data) | ||
559 | memcpy(blob->data, data, length); | ||
560 | |||
561 | ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, | ||
562 | true, drm_property_free_blob); | ||
563 | if (ret) { | ||
564 | kfree(blob); | ||
565 | return ERR_PTR(-EINVAL); | ||
566 | } | ||
567 | |||
568 | mutex_lock(&dev->mode_config.blob_lock); | ||
569 | list_add_tail(&blob->head_global, | ||
570 | &dev->mode_config.property_blob_list); | ||
571 | mutex_unlock(&dev->mode_config.blob_lock); | ||
572 | |||
573 | return blob; | ||
574 | } | ||
575 | EXPORT_SYMBOL(drm_property_create_blob); | ||
576 | |||
577 | /** | ||
578 | * drm_property_unreference_blob - Unreference a blob property | ||
579 | * | ||
580 | * Drop a reference on a blob property. May free the object. | ||
581 | * | ||
582 | * @blob: Pointer to blob property | ||
583 | */ | ||
584 | void drm_property_unreference_blob(struct drm_property_blob *blob) | ||
585 | { | ||
586 | if (!blob) | ||
587 | return; | ||
588 | |||
589 | drm_mode_object_unreference(&blob->base); | ||
590 | } | ||
591 | EXPORT_SYMBOL(drm_property_unreference_blob); | ||
592 | |||
593 | /** | ||
594 | * drm_property_destroy_user_blobs - destroy all blobs created by this client | ||
595 | * @dev: DRM device | ||
596 | * @file_priv: destroy all blobs owned by this file handle | ||
597 | */ | ||
598 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
599 | struct drm_file *file_priv) | ||
600 | { | ||
601 | struct drm_property_blob *blob, *bt; | ||
602 | |||
603 | /* | ||
604 | * When the file gets released that means no one else can access the | ||
605 | * blob list any more, so no need to grab dev->blob_lock. | ||
606 | */ | ||
607 | list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { | ||
608 | list_del_init(&blob->head_file); | ||
609 | drm_property_unreference_blob(blob); | ||
610 | } | ||
611 | } | ||
612 | |||
613 | /** | ||
614 | * drm_property_reference_blob - Take a reference on an existing property | ||
615 | * | ||
616 | * Take a new reference on an existing blob property. | ||
617 | * | ||
618 | * @blob: Pointer to blob property | ||
619 | */ | ||
620 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) | ||
621 | { | ||
622 | drm_mode_object_reference(&blob->base); | ||
623 | return blob; | ||
624 | } | ||
625 | EXPORT_SYMBOL(drm_property_reference_blob); | ||
626 | |||
627 | /** | ||
628 | * drm_property_lookup_blob - look up a blob property and take a reference | ||
629 | * @dev: drm device | ||
630 | * @id: id of the blob property | ||
631 | * | ||
632 | * If successful, this takes an additional reference to the blob property. | ||
633 | * callers need to make sure to eventually unreference the returned property | ||
634 | * again, using @drm_property_unreference_blob. | ||
635 | */ | ||
636 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
637 | uint32_t id) | ||
638 | { | ||
639 | struct drm_mode_object *obj; | ||
640 | struct drm_property_blob *blob = NULL; | ||
641 | |||
642 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); | ||
643 | if (obj) | ||
644 | blob = obj_to_blob(obj); | ||
645 | return blob; | ||
646 | } | ||
647 | EXPORT_SYMBOL(drm_property_lookup_blob); | ||
648 | |||
649 | /** | ||
650 | * drm_property_replace_global_blob - atomically replace existing blob property | ||
651 | * @dev: drm device | ||
652 | * @replace: location of blob property pointer to be replaced | ||
653 | * @length: length of data for new blob, or 0 for no data | ||
654 | * @data: content for new blob, or NULL for no data | ||
655 | * @obj_holds_id: optional object for property holding blob ID | ||
656 | * @prop_holds_id: optional property holding blob ID | ||
657 | * @return 0 on success or error on failure | ||
658 | * | ||
659 | * This function will atomically replace a global property in the blob list, | ||
660 | * optionally updating a property which holds the ID of that property. It is | ||
661 | * guaranteed to be atomic: no caller will be allowed to see intermediate | ||
662 | * results, and either the entire operation will succeed and clean up the | ||
663 | * previous property, or it will fail and the state will be unchanged. | ||
664 | * | ||
665 | * If length is 0 or data is NULL, no new blob will be created, and the holding | ||
666 | * property, if specified, will be set to 0. | ||
667 | * | ||
668 | * Access to the replace pointer is assumed to be protected by the caller, e.g. | ||
669 | * by holding the relevant modesetting object lock for its parent. | ||
670 | * | ||
671 | * For example, a drm_connector has a 'PATH' property, which contains the ID | ||
672 | * of a blob property with the value of the MST path information. Calling this | ||
673 | * function with replace pointing to the connector's path_blob_ptr, length and | ||
674 | * data set for the new path information, obj_holds_id set to the connector's | ||
675 | * base object, and prop_holds_id set to the path property name, will perform | ||
676 | * a completely atomic update. The access to path_blob_ptr is protected by the | ||
677 | * caller holding a lock on the connector. | ||
678 | */ | ||
679 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
680 | struct drm_property_blob **replace, | ||
681 | size_t length, | ||
682 | const void *data, | ||
683 | struct drm_mode_object *obj_holds_id, | ||
684 | struct drm_property *prop_holds_id) | ||
685 | { | ||
686 | struct drm_property_blob *new_blob = NULL; | ||
687 | struct drm_property_blob *old_blob = NULL; | ||
688 | int ret; | ||
689 | |||
690 | WARN_ON(replace == NULL); | ||
691 | |||
692 | old_blob = *replace; | ||
693 | |||
694 | if (length && data) { | ||
695 | new_blob = drm_property_create_blob(dev, length, data); | ||
696 | if (IS_ERR(new_blob)) | ||
697 | return PTR_ERR(new_blob); | ||
698 | } | ||
699 | |||
700 | /* This does not need to be synchronised with blob_lock, as the | ||
701 | * get_properties ioctl locks all modesetting objects, and | ||
702 | * obj_holds_id must be locked before calling here, so we cannot | ||
703 | * have its value out of sync with the list membership modified | ||
704 | * below under blob_lock. */ | ||
705 | if (obj_holds_id) { | ||
706 | ret = drm_object_property_set_value(obj_holds_id, | ||
707 | prop_holds_id, | ||
708 | new_blob ? | ||
709 | new_blob->base.id : 0); | ||
710 | if (ret != 0) | ||
711 | goto err_created; | ||
712 | } | ||
713 | |||
714 | drm_property_unreference_blob(old_blob); | ||
715 | *replace = new_blob; | ||
716 | |||
717 | return 0; | ||
718 | |||
719 | err_created: | ||
720 | drm_property_unreference_blob(new_blob); | ||
721 | return ret; | ||
722 | } | ||
723 | EXPORT_SYMBOL(drm_property_replace_global_blob); | ||
724 | |||
725 | /** | ||
726 | * drm_mode_getblob_ioctl - get the contents of a blob property value | ||
727 | * @dev: DRM device | ||
728 | * @data: ioctl data | ||
729 | * @file_priv: DRM file info | ||
730 | * | ||
731 | * This function retrieves the contents of a blob property. The value stored in | ||
732 | * an object's blob property is just a normal modeset object id. | ||
733 | * | ||
734 | * Called by the user via ioctl. | ||
735 | * | ||
736 | * Returns: | ||
737 | * Zero on success, negative errno on failure. | ||
738 | */ | ||
739 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
740 | void *data, struct drm_file *file_priv) | ||
741 | { | ||
742 | struct drm_mode_get_blob *out_resp = data; | ||
743 | struct drm_property_blob *blob; | ||
744 | int ret = 0; | ||
745 | void __user *blob_ptr; | ||
746 | |||
747 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
748 | return -EINVAL; | ||
749 | |||
750 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
751 | if (!blob) | ||
752 | return -ENOENT; | ||
753 | |||
754 | if (out_resp->length == blob->length) { | ||
755 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
756 | if (copy_to_user(blob_ptr, blob->data, blob->length)) { | ||
757 | ret = -EFAULT; | ||
758 | goto unref; | ||
759 | } | ||
760 | } | ||
761 | out_resp->length = blob->length; | ||
762 | unref: | ||
763 | drm_property_unreference_blob(blob); | ||
764 | |||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | /** | ||
769 | * drm_mode_createblob_ioctl - create a new blob property | ||
770 | * @dev: DRM device | ||
771 | * @data: ioctl data | ||
772 | * @file_priv: DRM file info | ||
773 | * | ||
774 | * This function creates a new blob property with user-defined values. In order | ||
775 | * to give us sensible validation and checking when creating, rather than at | ||
776 | * every potential use, we also require a type to be provided upfront. | ||
777 | * | ||
778 | * Called by the user via ioctl. | ||
779 | * | ||
780 | * Returns: | ||
781 | * Zero on success, negative errno on failure. | ||
782 | */ | ||
783 | int drm_mode_createblob_ioctl(struct drm_device *dev, | ||
784 | void *data, struct drm_file *file_priv) | ||
785 | { | ||
786 | struct drm_mode_create_blob *out_resp = data; | ||
787 | struct drm_property_blob *blob; | ||
788 | void __user *blob_ptr; | ||
789 | int ret = 0; | ||
790 | |||
791 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
792 | return -EINVAL; | ||
793 | |||
794 | blob = drm_property_create_blob(dev, out_resp->length, NULL); | ||
795 | if (IS_ERR(blob)) | ||
796 | return PTR_ERR(blob); | ||
797 | |||
798 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
799 | if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { | ||
800 | ret = -EFAULT; | ||
801 | goto out_blob; | ||
802 | } | ||
803 | |||
804 | /* Dropping the lock between create_blob and our access here is safe | ||
805 | * as only the same file_priv can remove the blob; at this point, it is | ||
806 | * not associated with any file_priv. */ | ||
807 | mutex_lock(&dev->mode_config.blob_lock); | ||
808 | out_resp->blob_id = blob->base.id; | ||
809 | list_add_tail(&blob->head_file, &file_priv->blobs); | ||
810 | mutex_unlock(&dev->mode_config.blob_lock); | ||
811 | |||
812 | return 0; | ||
813 | |||
814 | out_blob: | ||
815 | drm_property_unreference_blob(blob); | ||
816 | return ret; | ||
817 | } | ||
818 | |||
819 | /** | ||
820 | * drm_mode_destroyblob_ioctl - destroy a user blob property | ||
821 | * @dev: DRM device | ||
822 | * @data: ioctl data | ||
823 | * @file_priv: DRM file info | ||
824 | * | ||
825 | * Destroy an existing user-defined blob property. | ||
826 | * | ||
827 | * Called by the user via ioctl. | ||
828 | * | ||
829 | * Returns: | ||
830 | * Zero on success, negative errno on failure. | ||
831 | */ | ||
832 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | ||
833 | void *data, struct drm_file *file_priv) | ||
834 | { | ||
835 | struct drm_mode_destroy_blob *out_resp = data; | ||
836 | struct drm_property_blob *blob = NULL, *bt; | ||
837 | bool found = false; | ||
838 | int ret = 0; | ||
839 | |||
840 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
841 | return -EINVAL; | ||
842 | |||
843 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
844 | if (!blob) | ||
845 | return -ENOENT; | ||
846 | |||
847 | mutex_lock(&dev->mode_config.blob_lock); | ||
848 | /* Ensure the property was actually created by this user. */ | ||
849 | list_for_each_entry(bt, &file_priv->blobs, head_file) { | ||
850 | if (bt == blob) { | ||
851 | found = true; | ||
852 | break; | ||
853 | } | ||
854 | } | ||
855 | |||
856 | if (!found) { | ||
857 | ret = -EPERM; | ||
858 | goto err; | ||
859 | } | ||
860 | |||
861 | /* We must drop head_file here, because we may not be the last | ||
862 | * reference on the blob. */ | ||
863 | list_del_init(&blob->head_file); | ||
864 | mutex_unlock(&dev->mode_config.blob_lock); | ||
865 | |||
866 | /* One reference from lookup, and one from the filp. */ | ||
867 | drm_property_unreference_blob(blob); | ||
868 | drm_property_unreference_blob(blob); | ||
869 | |||
870 | return 0; | ||
871 | |||
872 | err: | ||
873 | mutex_unlock(&dev->mode_config.blob_lock); | ||
874 | drm_property_unreference_blob(blob); | ||
875 | |||
876 | return ret; | ||
877 | } | ||
878 | |||
879 | /* Some properties could refer to dynamic refcnt'd objects, or things that | ||
880 | * need special locking to handle lifetime issues (ie. to ensure the prop | ||
881 | * value doesn't become invalid part way through the property update due to | ||
882 | * race). The value returned by reference via 'obj' should be passed back | ||
883 | * to drm_property_change_valid_put() after the property is set (and the | ||
884 | * object to which the property is attached has a chance to take it's own | ||
885 | * reference). | ||
886 | */ | ||
887 | bool drm_property_change_valid_get(struct drm_property *property, | ||
888 | uint64_t value, struct drm_mode_object **ref) | ||
889 | { | ||
890 | int i; | ||
891 | |||
892 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | ||
893 | return false; | ||
894 | |||
895 | *ref = NULL; | ||
896 | |||
897 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | ||
898 | if (value < property->values[0] || value > property->values[1]) | ||
899 | return false; | ||
900 | return true; | ||
901 | } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { | ||
902 | int64_t svalue = U642I64(value); | ||
903 | |||
904 | if (svalue < U642I64(property->values[0]) || | ||
905 | svalue > U642I64(property->values[1])) | ||
906 | return false; | ||
907 | return true; | ||
908 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
909 | uint64_t valid_mask = 0; | ||
910 | |||
911 | for (i = 0; i < property->num_values; i++) | ||
912 | valid_mask |= (1ULL << property->values[i]); | ||
913 | return !(value & ~valid_mask); | ||
914 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { | ||
915 | struct drm_property_blob *blob; | ||
916 | |||
917 | if (value == 0) | ||
918 | return true; | ||
919 | |||
920 | blob = drm_property_lookup_blob(property->dev, value); | ||
921 | if (blob) { | ||
922 | *ref = &blob->base; | ||
923 | return true; | ||
924 | } else { | ||
925 | return false; | ||
926 | } | ||
927 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
928 | /* a zero value for an object property translates to null: */ | ||
929 | if (value == 0) | ||
930 | return true; | ||
931 | |||
932 | *ref = __drm_mode_object_find(property->dev, value, | ||
933 | property->values[0]); | ||
934 | return *ref != NULL; | ||
935 | } | ||
936 | |||
937 | for (i = 0; i < property->num_values; i++) | ||
938 | if (property->values[i] == value) | ||
939 | return true; | ||
940 | return false; | ||
941 | } | ||
942 | |||
943 | void drm_property_change_valid_put(struct drm_property *property, | ||
944 | struct drm_mode_object *ref) | ||
945 | { | ||
946 | if (!ref) | ||
947 | return; | ||
948 | |||
949 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
950 | drm_mode_object_unreference(ref); | ||
951 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
952 | drm_property_unreference_blob(obj_to_blob(ref)); | ||
953 | } | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 63f03490e987..3d33c90da9e5 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <drm/drm_modes.h> | 41 | #include <drm/drm_modes.h> |
42 | #include <drm/drm_connector.h> | 42 | #include <drm/drm_connector.h> |
43 | #include <drm/drm_encoder.h> | 43 | #include <drm/drm_encoder.h> |
44 | #include <drm/drm_property.h> | ||
44 | 45 | ||
45 | struct drm_device; | 46 | struct drm_device; |
46 | struct drm_mode_set; | 47 | struct drm_mode_set; |
@@ -82,33 +83,6 @@ struct drm_tile_group { | |||
82 | u8 group_data[8]; | 83 | u8 group_data[8]; |
83 | }; | 84 | }; |
84 | 85 | ||
85 | struct drm_property_blob { | ||
86 | struct drm_mode_object base; | ||
87 | struct drm_device *dev; | ||
88 | struct list_head head_global; | ||
89 | struct list_head head_file; | ||
90 | size_t length; | ||
91 | unsigned char data[]; | ||
92 | }; | ||
93 | |||
94 | struct drm_property_enum { | ||
95 | uint64_t value; | ||
96 | struct list_head head; | ||
97 | char name[DRM_PROP_NAME_LEN]; | ||
98 | }; | ||
99 | |||
100 | struct drm_property { | ||
101 | struct list_head head; | ||
102 | struct drm_mode_object base; | ||
103 | uint32_t flags; | ||
104 | char name[DRM_PROP_NAME_LEN]; | ||
105 | uint32_t num_values; | ||
106 | uint64_t *values; | ||
107 | struct drm_device *dev; | ||
108 | |||
109 | struct list_head enum_list; | ||
110 | }; | ||
111 | |||
112 | struct drm_crtc; | 86 | struct drm_crtc; |
113 | struct drm_encoder; | 87 | struct drm_encoder; |
114 | struct drm_pending_vblank_event; | 88 | struct drm_pending_vblank_event; |
@@ -2026,15 +2000,9 @@ struct drm_mode_config { | |||
2026 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) | 2000 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) |
2027 | #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) | 2001 | #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) |
2028 | #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) | 2002 | #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) |
2029 | #define obj_to_property(x) container_of(x, struct drm_property, base) | ||
2030 | #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) | 2003 | #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) |
2031 | #define obj_to_plane(x) container_of(x, struct drm_plane, base) | 2004 | #define obj_to_plane(x) container_of(x, struct drm_plane, base) |
2032 | 2005 | ||
2033 | struct drm_prop_enum_list { | ||
2034 | int type; | ||
2035 | char *name; | ||
2036 | }; | ||
2037 | |||
2038 | extern __printf(6, 7) | 2006 | extern __printf(6, 7) |
2039 | int drm_crtc_init_with_planes(struct drm_device *dev, | 2007 | int drm_crtc_init_with_planes(struct drm_device *dev, |
2040 | struct drm_crtc *crtc, | 2008 | struct drm_crtc *crtc, |
@@ -2107,52 +2075,6 @@ extern void drm_mode_config_init(struct drm_device *dev); | |||
2107 | extern void drm_mode_config_reset(struct drm_device *dev); | 2075 | extern void drm_mode_config_reset(struct drm_device *dev); |
2108 | extern void drm_mode_config_cleanup(struct drm_device *dev); | 2076 | extern void drm_mode_config_cleanup(struct drm_device *dev); |
2109 | 2077 | ||
2110 | static inline bool drm_property_type_is(struct drm_property *property, | ||
2111 | uint32_t type) | ||
2112 | { | ||
2113 | /* instanceof for props.. handles extended type vs original types: */ | ||
2114 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
2115 | return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; | ||
2116 | return property->flags & type; | ||
2117 | } | ||
2118 | |||
2119 | extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
2120 | const char *name, int num_values); | ||
2121 | extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
2122 | const char *name, | ||
2123 | const struct drm_prop_enum_list *props, | ||
2124 | int num_values); | ||
2125 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
2126 | int flags, const char *name, | ||
2127 | const struct drm_prop_enum_list *props, | ||
2128 | int num_props, | ||
2129 | uint64_t supported_bits); | ||
2130 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
2131 | const char *name, | ||
2132 | uint64_t min, uint64_t max); | ||
2133 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
2134 | int flags, const char *name, | ||
2135 | int64_t min, int64_t max); | ||
2136 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
2137 | int flags, const char *name, uint32_t type); | ||
2138 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
2139 | const char *name); | ||
2140 | struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, | ||
2141 | size_t length, | ||
2142 | const void *data); | ||
2143 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
2144 | uint32_t id); | ||
2145 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
2146 | struct drm_property_blob **replace, | ||
2147 | size_t length, | ||
2148 | const void *data, | ||
2149 | struct drm_mode_object *obj_holds_id, | ||
2150 | struct drm_property *prop_holds_id); | ||
2151 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob); | ||
2152 | void drm_property_unreference_blob(struct drm_property_blob *blob); | ||
2153 | extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | ||
2154 | extern int drm_property_add_enum(struct drm_property *property, int index, | ||
2155 | uint64_t value, const char *name); | ||
2156 | extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | 2078 | extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, |
2157 | int gamma_size); | 2079 | int gamma_size); |
2158 | 2080 | ||
@@ -2202,14 +2124,6 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, | |||
2202 | return mo ? obj_to_crtc(mo) : NULL; | 2124 | return mo ? obj_to_crtc(mo) : NULL; |
2203 | } | 2125 | } |
2204 | 2126 | ||
2205 | static inline struct drm_property *drm_property_find(struct drm_device *dev, | ||
2206 | uint32_t id) | ||
2207 | { | ||
2208 | struct drm_mode_object *mo; | ||
2209 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY); | ||
2210 | return mo ? obj_to_property(mo) : NULL; | ||
2211 | } | ||
2212 | |||
2213 | /* | 2127 | /* |
2214 | * Extract a degamma/gamma LUT value provided by user and round it to the | 2128 | * Extract a degamma/gamma LUT value provided by user and round it to the |
2215 | * precision supported by the hardware. | 2129 | * precision supported by the hardware. |
diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h new file mode 100644 index 000000000000..ac40069358c7 --- /dev/null +++ b/include/drm/drm_property.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __DRM_PROPERTY_H__ | ||
24 | #define __DRM_PROPERTY_H__ | ||
25 | |||
26 | #include <linux/list.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <drm/drm_mode_object.h> | ||
29 | |||
30 | struct drm_property_blob { | ||
31 | struct drm_mode_object base; | ||
32 | struct drm_device *dev; | ||
33 | struct list_head head_global; | ||
34 | struct list_head head_file; | ||
35 | size_t length; | ||
36 | unsigned char data[]; | ||
37 | }; | ||
38 | |||
39 | struct drm_property_enum { | ||
40 | uint64_t value; | ||
41 | struct list_head head; | ||
42 | char name[DRM_PROP_NAME_LEN]; | ||
43 | }; | ||
44 | |||
45 | struct drm_property { | ||
46 | struct list_head head; | ||
47 | struct drm_mode_object base; | ||
48 | uint32_t flags; | ||
49 | char name[DRM_PROP_NAME_LEN]; | ||
50 | uint32_t num_values; | ||
51 | uint64_t *values; | ||
52 | struct drm_device *dev; | ||
53 | |||
54 | struct list_head enum_list; | ||
55 | }; | ||
56 | |||
57 | struct drm_prop_enum_list { | ||
58 | int type; | ||
59 | char *name; | ||
60 | }; | ||
61 | |||
62 | #define obj_to_property(x) container_of(x, struct drm_property, base) | ||
63 | |||
64 | static inline bool drm_property_type_is(struct drm_property *property, | ||
65 | uint32_t type) | ||
66 | { | ||
67 | /* instanceof for props.. handles extended type vs original types: */ | ||
68 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
69 | return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; | ||
70 | return property->flags & type; | ||
71 | } | ||
72 | |||
73 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
74 | const char *name, int num_values); | ||
75 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
76 | const char *name, | ||
77 | const struct drm_prop_enum_list *props, | ||
78 | int num_values); | ||
79 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
80 | int flags, const char *name, | ||
81 | const struct drm_prop_enum_list *props, | ||
82 | int num_props, | ||
83 | uint64_t supported_bits); | ||
84 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
85 | const char *name, | ||
86 | uint64_t min, uint64_t max); | ||
87 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
88 | int flags, const char *name, | ||
89 | int64_t min, int64_t max); | ||
90 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
91 | int flags, const char *name, uint32_t type); | ||
92 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
93 | const char *name); | ||
94 | int drm_property_add_enum(struct drm_property *property, int index, | ||
95 | uint64_t value, const char *name); | ||
96 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | ||
97 | |||
98 | struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, | ||
99 | size_t length, | ||
100 | const void *data); | ||
101 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
102 | uint32_t id); | ||
103 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
104 | struct drm_property_blob **replace, | ||
105 | size_t length, | ||
106 | const void *data, | ||
107 | struct drm_mode_object *obj_holds_id, | ||
108 | struct drm_property *prop_holds_id); | ||
109 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob); | ||
110 | void drm_property_unreference_blob(struct drm_property_blob *blob); | ||
111 | |||
112 | static inline struct drm_property *drm_property_find(struct drm_device *dev, | ||
113 | uint32_t id) | ||
114 | { | ||
115 | struct drm_mode_object *mo; | ||
116 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY); | ||
117 | return mo ? obj_to_property(mo) : NULL; | ||
118 | } | ||
119 | |||
120 | #endif | ||