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 /drivers/gpu/drm/drm_crtc.c | |
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
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 926 |
1 files changed, 0 insertions, 926 deletions
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) |