diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 191 |
1 files changed, 147 insertions, 44 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e7e92429d10f..fc83bb9eb514 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | * Dave Airlie <airlied@linux.ie> | 29 | * Dave Airlie <airlied@linux.ie> |
30 | * Jesse Barnes <jesse.barnes@intel.com> | 30 | * Jesse Barnes <jesse.barnes@intel.com> |
31 | */ | 31 | */ |
32 | #include <linux/ctype.h> | ||
32 | #include <linux/list.h> | 33 | #include <linux/list.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
34 | #include <linux/export.h> | 35 | #include <linux/export.h> |
@@ -91,7 +92,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); | |||
91 | 92 | ||
92 | /* Avoid boilerplate. I'm tired of typing. */ | 93 | /* Avoid boilerplate. I'm tired of typing. */ |
93 | #define DRM_ENUM_NAME_FN(fnname, list) \ | 94 | #define DRM_ENUM_NAME_FN(fnname, list) \ |
94 | char *fnname(int val) \ | 95 | const char *fnname(int val) \ |
95 | { \ | 96 | { \ |
96 | int i; \ | 97 | int i; \ |
97 | for (i = 0; i < ARRAY_SIZE(list); i++) { \ | 98 | for (i = 0; i < ARRAY_SIZE(list); i++) { \ |
@@ -104,7 +105,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); | |||
104 | /* | 105 | /* |
105 | * Global properties | 106 | * Global properties |
106 | */ | 107 | */ |
107 | static struct drm_prop_enum_list drm_dpms_enum_list[] = | 108 | static const struct drm_prop_enum_list drm_dpms_enum_list[] = |
108 | { { DRM_MODE_DPMS_ON, "On" }, | 109 | { { DRM_MODE_DPMS_ON, "On" }, |
109 | { DRM_MODE_DPMS_STANDBY, "Standby" }, | 110 | { DRM_MODE_DPMS_STANDBY, "Standby" }, |
110 | { DRM_MODE_DPMS_SUSPEND, "Suspend" }, | 111 | { DRM_MODE_DPMS_SUSPEND, "Suspend" }, |
@@ -116,7 +117,7 @@ DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) | |||
116 | /* | 117 | /* |
117 | * Optional properties | 118 | * Optional properties |
118 | */ | 119 | */ |
119 | static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = | 120 | static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = |
120 | { | 121 | { |
121 | { DRM_MODE_SCALE_NONE, "None" }, | 122 | { DRM_MODE_SCALE_NONE, "None" }, |
122 | { DRM_MODE_SCALE_FULLSCREEN, "Full" }, | 123 | { DRM_MODE_SCALE_FULLSCREEN, "Full" }, |
@@ -124,7 +125,7 @@ static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = | |||
124 | { DRM_MODE_SCALE_ASPECT, "Full aspect" }, | 125 | { DRM_MODE_SCALE_ASPECT, "Full aspect" }, |
125 | }; | 126 | }; |
126 | 127 | ||
127 | static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = | 128 | static const struct drm_prop_enum_list drm_dithering_mode_enum_list[] = |
128 | { | 129 | { |
129 | { DRM_MODE_DITHERING_OFF, "Off" }, | 130 | { DRM_MODE_DITHERING_OFF, "Off" }, |
130 | { DRM_MODE_DITHERING_ON, "On" }, | 131 | { DRM_MODE_DITHERING_ON, "On" }, |
@@ -134,7 +135,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = | |||
134 | /* | 135 | /* |
135 | * Non-global properties, but "required" for certain connectors. | 136 | * Non-global properties, but "required" for certain connectors. |
136 | */ | 137 | */ |
137 | static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = | 138 | static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = |
138 | { | 139 | { |
139 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ | 140 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ |
140 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ | 141 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
@@ -143,7 +144,7 @@ static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = | |||
143 | 144 | ||
144 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) | 145 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) |
145 | 146 | ||
146 | static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = | 147 | static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = |
147 | { | 148 | { |
148 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | 149 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
149 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ | 150 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
@@ -153,7 +154,7 @@ static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = | |||
153 | DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, | 154 | DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, |
154 | drm_dvi_i_subconnector_enum_list) | 155 | drm_dvi_i_subconnector_enum_list) |
155 | 156 | ||
156 | static struct drm_prop_enum_list drm_tv_select_enum_list[] = | 157 | static const struct drm_prop_enum_list drm_tv_select_enum_list[] = |
157 | { | 158 | { |
158 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ | 159 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ |
159 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ | 160 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
@@ -164,7 +165,7 @@ static struct drm_prop_enum_list drm_tv_select_enum_list[] = | |||
164 | 165 | ||
165 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) | 166 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) |
166 | 167 | ||
167 | static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = | 168 | static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = |
168 | { | 169 | { |
169 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | 170 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
170 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ | 171 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
@@ -176,7 +177,7 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = | |||
176 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, | 177 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
177 | drm_tv_subconnector_enum_list) | 178 | drm_tv_subconnector_enum_list) |
178 | 179 | ||
179 | static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { | 180 | static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { |
180 | { DRM_MODE_DIRTY_OFF, "Off" }, | 181 | { DRM_MODE_DIRTY_OFF, "Off" }, |
181 | { DRM_MODE_DIRTY_ON, "On" }, | 182 | { DRM_MODE_DIRTY_ON, "On" }, |
182 | { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, | 183 | { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, |
@@ -184,7 +185,7 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { | |||
184 | 185 | ||
185 | struct drm_conn_prop_enum_list { | 186 | struct drm_conn_prop_enum_list { |
186 | int type; | 187 | int type; |
187 | char *name; | 188 | const char *name; |
188 | int count; | 189 | int count; |
189 | }; | 190 | }; |
190 | 191 | ||
@@ -210,7 +211,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = | |||
210 | { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, | 211 | { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, |
211 | }; | 212 | }; |
212 | 213 | ||
213 | static struct drm_prop_enum_list drm_encoder_enum_list[] = | 214 | static const struct drm_prop_enum_list drm_encoder_enum_list[] = |
214 | { { DRM_MODE_ENCODER_NONE, "None" }, | 215 | { { DRM_MODE_ENCODER_NONE, "None" }, |
215 | { DRM_MODE_ENCODER_DAC, "DAC" }, | 216 | { DRM_MODE_ENCODER_DAC, "DAC" }, |
216 | { DRM_MODE_ENCODER_TMDS, "TMDS" }, | 217 | { DRM_MODE_ENCODER_TMDS, "TMDS" }, |
@@ -219,7 +220,7 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = | |||
219 | { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, | 220 | { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, |
220 | }; | 221 | }; |
221 | 222 | ||
222 | char *drm_get_encoder_name(struct drm_encoder *encoder) | 223 | const char *drm_get_encoder_name(const struct drm_encoder *encoder) |
223 | { | 224 | { |
224 | static char buf[32]; | 225 | static char buf[32]; |
225 | 226 | ||
@@ -230,7 +231,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder) | |||
230 | } | 231 | } |
231 | EXPORT_SYMBOL(drm_get_encoder_name); | 232 | EXPORT_SYMBOL(drm_get_encoder_name); |
232 | 233 | ||
233 | char *drm_get_connector_name(struct drm_connector *connector) | 234 | const char *drm_get_connector_name(const struct drm_connector *connector) |
234 | { | 235 | { |
235 | static char buf[32]; | 236 | static char buf[32]; |
236 | 237 | ||
@@ -241,7 +242,7 @@ char *drm_get_connector_name(struct drm_connector *connector) | |||
241 | } | 242 | } |
242 | EXPORT_SYMBOL(drm_get_connector_name); | 243 | EXPORT_SYMBOL(drm_get_connector_name); |
243 | 244 | ||
244 | char *drm_get_connector_status_name(enum drm_connector_status status) | 245 | const char *drm_get_connector_status_name(enum drm_connector_status status) |
245 | { | 246 | { |
246 | if (status == connector_status_connected) | 247 | if (status == connector_status_connected) |
247 | return "connected"; | 248 | return "connected"; |
@@ -252,6 +253,28 @@ char *drm_get_connector_status_name(enum drm_connector_status status) | |||
252 | } | 253 | } |
253 | EXPORT_SYMBOL(drm_get_connector_status_name); | 254 | EXPORT_SYMBOL(drm_get_connector_status_name); |
254 | 255 | ||
256 | static char printable_char(int c) | ||
257 | { | ||
258 | return isascii(c) && isprint(c) ? c : '?'; | ||
259 | } | ||
260 | |||
261 | const char *drm_get_format_name(uint32_t format) | ||
262 | { | ||
263 | static char buf[32]; | ||
264 | |||
265 | snprintf(buf, sizeof(buf), | ||
266 | "%c%c%c%c %s-endian (0x%08x)", | ||
267 | printable_char(format & 0xff), | ||
268 | printable_char((format >> 8) & 0xff), | ||
269 | printable_char((format >> 16) & 0xff), | ||
270 | printable_char((format >> 24) & 0x7f), | ||
271 | format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", | ||
272 | format); | ||
273 | |||
274 | return buf; | ||
275 | } | ||
276 | EXPORT_SYMBOL(drm_get_format_name); | ||
277 | |||
255 | /** | 278 | /** |
256 | * drm_mode_object_get - allocate a new modeset identifier | 279 | * drm_mode_object_get - allocate a new modeset identifier |
257 | * @dev: DRM device | 280 | * @dev: DRM device |
@@ -569,16 +592,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
569 | } | 592 | } |
570 | 593 | ||
571 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { | 594 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { |
572 | if (plane->fb == fb) { | 595 | if (plane->fb == fb) |
573 | /* should turn off the crtc */ | 596 | drm_plane_force_disable(plane); |
574 | ret = plane->funcs->disable_plane(plane); | ||
575 | if (ret) | ||
576 | DRM_ERROR("failed to disable plane with busy fb\n"); | ||
577 | /* disconnect the plane from the fb and crtc: */ | ||
578 | __drm_framebuffer_unreference(plane->fb); | ||
579 | plane->fb = NULL; | ||
580 | plane->crtc = NULL; | ||
581 | } | ||
582 | } | 597 | } |
583 | drm_modeset_unlock_all(dev); | 598 | drm_modeset_unlock_all(dev); |
584 | } | 599 | } |
@@ -593,7 +608,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove); | |||
593 | * @crtc: CRTC object to init | 608 | * @crtc: CRTC object to init |
594 | * @funcs: callbacks for the new CRTC | 609 | * @funcs: callbacks for the new CRTC |
595 | * | 610 | * |
596 | * Inits a new object created as base part of an driver crtc object. | 611 | * Inits a new object created as base part of a driver crtc object. |
597 | * | 612 | * |
598 | * RETURNS: | 613 | * RETURNS: |
599 | * Zero on success, error code on failure. | 614 | * Zero on success, error code on failure. |
@@ -628,11 +643,12 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
628 | EXPORT_SYMBOL(drm_crtc_init); | 643 | EXPORT_SYMBOL(drm_crtc_init); |
629 | 644 | ||
630 | /** | 645 | /** |
631 | * drm_crtc_cleanup - Cleans up the core crtc usage. | 646 | * drm_crtc_cleanup - Clean up the core crtc usage |
632 | * @crtc: CRTC to cleanup | 647 | * @crtc: CRTC to cleanup |
633 | * | 648 | * |
634 | * Cleanup @crtc. Removes from drm modesetting space | 649 | * This function cleans up @crtc and removes it from the DRM mode setting |
635 | * does NOT free object, caller does that. | 650 | * core. Note that the function does *not* free the crtc structure itself, |
651 | * this is the responsibility of the caller. | ||
636 | */ | 652 | */ |
637 | void drm_crtc_cleanup(struct drm_crtc *crtc) | 653 | void drm_crtc_cleanup(struct drm_crtc *crtc) |
638 | { | 654 | { |
@@ -657,7 +673,7 @@ EXPORT_SYMBOL(drm_crtc_cleanup); | |||
657 | void drm_mode_probed_add(struct drm_connector *connector, | 673 | void drm_mode_probed_add(struct drm_connector *connector, |
658 | struct drm_display_mode *mode) | 674 | struct drm_display_mode *mode) |
659 | { | 675 | { |
660 | list_add(&mode->head, &connector->probed_modes); | 676 | list_add_tail(&mode->head, &connector->probed_modes); |
661 | } | 677 | } |
662 | EXPORT_SYMBOL(drm_mode_probed_add); | 678 | EXPORT_SYMBOL(drm_mode_probed_add); |
663 | 679 | ||
@@ -803,6 +819,21 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) | |||
803 | } | 819 | } |
804 | EXPORT_SYMBOL(drm_encoder_cleanup); | 820 | EXPORT_SYMBOL(drm_encoder_cleanup); |
805 | 821 | ||
822 | /** | ||
823 | * drm_plane_init - Initialise a new plane object | ||
824 | * @dev: DRM device | ||
825 | * @plane: plane object to init | ||
826 | * @possible_crtcs: bitmask of possible CRTCs | ||
827 | * @funcs: callbacks for the new plane | ||
828 | * @formats: array of supported formats (%DRM_FORMAT_*) | ||
829 | * @format_count: number of elements in @formats | ||
830 | * @priv: plane is private (hidden from userspace)? | ||
831 | * | ||
832 | * Inits a new object created as base part of a driver plane object. | ||
833 | * | ||
834 | * RETURNS: | ||
835 | * Zero on success, error code on failure. | ||
836 | */ | ||
806 | int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | 837 | int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, |
807 | unsigned long possible_crtcs, | 838 | unsigned long possible_crtcs, |
808 | const struct drm_plane_funcs *funcs, | 839 | const struct drm_plane_funcs *funcs, |
@@ -851,6 +882,14 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
851 | } | 882 | } |
852 | EXPORT_SYMBOL(drm_plane_init); | 883 | EXPORT_SYMBOL(drm_plane_init); |
853 | 884 | ||
885 | /** | ||
886 | * drm_plane_cleanup - Clean up the core plane usage | ||
887 | * @plane: plane to cleanup | ||
888 | * | ||
889 | * This function cleans up @plane and removes it from the DRM mode setting | ||
890 | * core. Note that the function does *not* free the plane structure itself, | ||
891 | * this is the responsibility of the caller. | ||
892 | */ | ||
854 | void drm_plane_cleanup(struct drm_plane *plane) | 893 | void drm_plane_cleanup(struct drm_plane *plane) |
855 | { | 894 | { |
856 | struct drm_device *dev = plane->dev; | 895 | struct drm_device *dev = plane->dev; |
@@ -868,6 +907,32 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
868 | EXPORT_SYMBOL(drm_plane_cleanup); | 907 | EXPORT_SYMBOL(drm_plane_cleanup); |
869 | 908 | ||
870 | /** | 909 | /** |
910 | * drm_plane_force_disable - Forcibly disable a plane | ||
911 | * @plane: plane to disable | ||
912 | * | ||
913 | * Forces the plane to be disabled. | ||
914 | * | ||
915 | * Used when the plane's current framebuffer is destroyed, | ||
916 | * and when restoring fbdev mode. | ||
917 | */ | ||
918 | void drm_plane_force_disable(struct drm_plane *plane) | ||
919 | { | ||
920 | int ret; | ||
921 | |||
922 | if (!plane->fb) | ||
923 | return; | ||
924 | |||
925 | ret = plane->funcs->disable_plane(plane); | ||
926 | if (ret) | ||
927 | DRM_ERROR("failed to disable plane with busy fb\n"); | ||
928 | /* disconnect the plane from the fb and crtc: */ | ||
929 | __drm_framebuffer_unreference(plane->fb); | ||
930 | plane->fb = NULL; | ||
931 | plane->crtc = NULL; | ||
932 | } | ||
933 | EXPORT_SYMBOL(drm_plane_force_disable); | ||
934 | |||
935 | /** | ||
871 | * drm_mode_create - create a new display mode | 936 | * drm_mode_create - create a new display mode |
872 | * @dev: DRM device | 937 | * @dev: DRM device |
873 | * | 938 | * |
@@ -1740,7 +1805,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
1740 | 1805 | ||
1741 | plane_resp->plane_id = plane->base.id; | 1806 | plane_resp->plane_id = plane->base.id; |
1742 | plane_resp->possible_crtcs = plane->possible_crtcs; | 1807 | plane_resp->possible_crtcs = plane->possible_crtcs; |
1743 | plane_resp->gamma_size = plane->gamma_size; | 1808 | plane_resp->gamma_size = 0; |
1744 | 1809 | ||
1745 | /* | 1810 | /* |
1746 | * This ioctl is called twice, once to determine how much space is | 1811 | * This ioctl is called twice, once to determine how much space is |
@@ -1834,7 +1899,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1834 | if (fb->pixel_format == plane->format_types[i]) | 1899 | if (fb->pixel_format == plane->format_types[i]) |
1835 | break; | 1900 | break; |
1836 | if (i == plane->format_count) { | 1901 | if (i == plane->format_count) { |
1837 | DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); | 1902 | DRM_DEBUG_KMS("Invalid pixel format %s\n", |
1903 | drm_get_format_name(fb->pixel_format)); | ||
1838 | ret = -EINVAL; | 1904 | ret = -EINVAL; |
1839 | goto out; | 1905 | goto out; |
1840 | } | 1906 | } |
@@ -1906,18 +1972,31 @@ out: | |||
1906 | int drm_mode_set_config_internal(struct drm_mode_set *set) | 1972 | int drm_mode_set_config_internal(struct drm_mode_set *set) |
1907 | { | 1973 | { |
1908 | struct drm_crtc *crtc = set->crtc; | 1974 | struct drm_crtc *crtc = set->crtc; |
1909 | struct drm_framebuffer *fb, *old_fb; | 1975 | struct drm_framebuffer *fb; |
1976 | struct drm_crtc *tmp; | ||
1910 | int ret; | 1977 | int ret; |
1911 | 1978 | ||
1912 | old_fb = crtc->fb; | 1979 | /* |
1980 | * NOTE: ->set_config can also disable other crtcs (if we steal all | ||
1981 | * connectors from it), hence we need to refcount the fbs across all | ||
1982 | * crtcs. Atomic modeset will have saner semantics ... | ||
1983 | */ | ||
1984 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) | ||
1985 | tmp->old_fb = tmp->fb; | ||
1986 | |||
1913 | fb = set->fb; | 1987 | fb = set->fb; |
1914 | 1988 | ||
1915 | ret = crtc->funcs->set_config(set); | 1989 | ret = crtc->funcs->set_config(set); |
1916 | if (ret == 0) { | 1990 | if (ret == 0) { |
1917 | if (old_fb) | 1991 | /* crtc->fb must be updated by ->set_config, enforces this. */ |
1918 | drm_framebuffer_unreference(old_fb); | 1992 | WARN_ON(fb != crtc->fb); |
1919 | if (fb) | 1993 | } |
1920 | drm_framebuffer_reference(fb); | 1994 | |
1995 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { | ||
1996 | if (tmp->fb) | ||
1997 | drm_framebuffer_reference(tmp->fb); | ||
1998 | if (tmp->old_fb) | ||
1999 | drm_framebuffer_unreference(tmp->old_fb); | ||
1921 | } | 2000 | } |
1922 | 2001 | ||
1923 | return ret; | 2002 | return ret; |
@@ -2099,10 +2178,10 @@ out: | |||
2099 | return ret; | 2178 | return ret; |
2100 | } | 2179 | } |
2101 | 2180 | ||
2102 | int drm_mode_cursor_ioctl(struct drm_device *dev, | 2181 | static int drm_mode_cursor_common(struct drm_device *dev, |
2103 | void *data, struct drm_file *file_priv) | 2182 | struct drm_mode_cursor2 *req, |
2183 | struct drm_file *file_priv) | ||
2104 | { | 2184 | { |
2105 | struct drm_mode_cursor *req = data; | ||
2106 | struct drm_mode_object *obj; | 2185 | struct drm_mode_object *obj; |
2107 | struct drm_crtc *crtc; | 2186 | struct drm_crtc *crtc; |
2108 | int ret = 0; | 2187 | int ret = 0; |
@@ -2122,13 +2201,17 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
2122 | 2201 | ||
2123 | mutex_lock(&crtc->mutex); | 2202 | mutex_lock(&crtc->mutex); |
2124 | if (req->flags & DRM_MODE_CURSOR_BO) { | 2203 | if (req->flags & DRM_MODE_CURSOR_BO) { |
2125 | if (!crtc->funcs->cursor_set) { | 2204 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { |
2126 | ret = -ENXIO; | 2205 | ret = -ENXIO; |
2127 | goto out; | 2206 | goto out; |
2128 | } | 2207 | } |
2129 | /* Turns off the cursor if handle is 0 */ | 2208 | /* Turns off the cursor if handle is 0 */ |
2130 | ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, | 2209 | if (crtc->funcs->cursor_set2) |
2131 | req->width, req->height); | 2210 | ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, |
2211 | req->width, req->height, req->hot_x, req->hot_y); | ||
2212 | else | ||
2213 | ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, | ||
2214 | req->width, req->height); | ||
2132 | } | 2215 | } |
2133 | 2216 | ||
2134 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | 2217 | if (req->flags & DRM_MODE_CURSOR_MOVE) { |
@@ -2143,6 +2226,25 @@ out: | |||
2143 | mutex_unlock(&crtc->mutex); | 2226 | mutex_unlock(&crtc->mutex); |
2144 | 2227 | ||
2145 | return ret; | 2228 | return ret; |
2229 | |||
2230 | } | ||
2231 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
2232 | void *data, struct drm_file *file_priv) | ||
2233 | { | ||
2234 | struct drm_mode_cursor *req = data; | ||
2235 | struct drm_mode_cursor2 new_req; | ||
2236 | |||
2237 | memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); | ||
2238 | new_req.hot_x = new_req.hot_y = 0; | ||
2239 | |||
2240 | return drm_mode_cursor_common(dev, &new_req, file_priv); | ||
2241 | } | ||
2242 | |||
2243 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
2244 | void *data, struct drm_file *file_priv) | ||
2245 | { | ||
2246 | struct drm_mode_cursor2 *req = data; | ||
2247 | return drm_mode_cursor_common(dev, req, file_priv); | ||
2146 | } | 2248 | } |
2147 | 2249 | ||
2148 | /* Original addfb only supported RGB formats, so figure out which one */ | 2250 | /* Original addfb only supported RGB formats, so figure out which one */ |
@@ -2312,7 +2414,8 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | |||
2312 | 2414 | ||
2313 | ret = format_check(r); | 2415 | ret = format_check(r); |
2314 | if (ret) { | 2416 | if (ret) { |
2315 | DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format); | 2417 | DRM_DEBUG_KMS("bad framebuffer format %s\n", |
2418 | drm_get_format_name(r->pixel_format)); | ||
2316 | return ret; | 2419 | return ret; |
2317 | } | 2420 | } |
2318 | 2421 | ||