diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5cae0b3eee9b..4fe321dc900c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -125,6 +125,15 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = | |||
125 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, | 125 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
126 | drm_tv_subconnector_enum_list) | 126 | drm_tv_subconnector_enum_list) |
127 | 127 | ||
128 | static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { | ||
129 | { DRM_MODE_DIRTY_OFF, "Off" }, | ||
130 | { DRM_MODE_DIRTY_ON, "On" }, | ||
131 | { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, | ||
132 | }; | ||
133 | |||
134 | DRM_ENUM_NAME_FN(drm_get_dirty_info_name, | ||
135 | drm_dirty_info_enum_list) | ||
136 | |||
128 | struct drm_conn_prop_enum_list { | 137 | struct drm_conn_prop_enum_list { |
129 | int type; | 138 | int type; |
130 | char *name; | 139 | char *name; |
@@ -802,6 +811,36 @@ int drm_mode_create_dithering_property(struct drm_device *dev) | |||
802 | EXPORT_SYMBOL(drm_mode_create_dithering_property); | 811 | EXPORT_SYMBOL(drm_mode_create_dithering_property); |
803 | 812 | ||
804 | /** | 813 | /** |
814 | * drm_mode_create_dirty_property - create dirty property | ||
815 | * @dev: DRM device | ||
816 | * | ||
817 | * Called by a driver the first time it's needed, must be attached to desired | ||
818 | * connectors. | ||
819 | */ | ||
820 | int drm_mode_create_dirty_info_property(struct drm_device *dev) | ||
821 | { | ||
822 | struct drm_property *dirty_info; | ||
823 | int i; | ||
824 | |||
825 | if (dev->mode_config.dirty_info_property) | ||
826 | return 0; | ||
827 | |||
828 | dirty_info = | ||
829 | drm_property_create(dev, DRM_MODE_PROP_ENUM | | ||
830 | DRM_MODE_PROP_IMMUTABLE, | ||
831 | "dirty", | ||
832 | ARRAY_SIZE(drm_dirty_info_enum_list)); | ||
833 | for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++) | ||
834 | drm_property_add_enum(dirty_info, i, | ||
835 | drm_dirty_info_enum_list[i].type, | ||
836 | drm_dirty_info_enum_list[i].name); | ||
837 | dev->mode_config.dirty_info_property = dirty_info; | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | ||
842 | |||
843 | /** | ||
805 | * drm_mode_config_init - initialize DRM mode_configuration structure | 844 | * drm_mode_config_init - initialize DRM mode_configuration structure |
806 | * @dev: DRM device | 845 | * @dev: DRM device |
807 | * | 846 | * |
@@ -1753,6 +1792,71 @@ out: | |||
1753 | return ret; | 1792 | return ret; |
1754 | } | 1793 | } |
1755 | 1794 | ||
1795 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
1796 | void *data, struct drm_file *file_priv) | ||
1797 | { | ||
1798 | struct drm_clip_rect __user *clips_ptr; | ||
1799 | struct drm_clip_rect *clips = NULL; | ||
1800 | struct drm_mode_fb_dirty_cmd *r = data; | ||
1801 | struct drm_mode_object *obj; | ||
1802 | struct drm_framebuffer *fb; | ||
1803 | unsigned flags; | ||
1804 | int num_clips; | ||
1805 | int ret = 0; | ||
1806 | |||
1807 | mutex_lock(&dev->mode_config.mutex); | ||
1808 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | ||
1809 | if (!obj) { | ||
1810 | DRM_ERROR("invalid framebuffer id\n"); | ||
1811 | ret = -EINVAL; | ||
1812 | goto out_err1; | ||
1813 | } | ||
1814 | fb = obj_to_fb(obj); | ||
1815 | |||
1816 | num_clips = r->num_clips; | ||
1817 | clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr; | ||
1818 | |||
1819 | if (!num_clips != !clips_ptr) { | ||
1820 | ret = -EINVAL; | ||
1821 | goto out_err1; | ||
1822 | } | ||
1823 | |||
1824 | flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; | ||
1825 | |||
1826 | /* If userspace annotates copy, clips must come in pairs */ | ||
1827 | if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { | ||
1828 | ret = -EINVAL; | ||
1829 | goto out_err1; | ||
1830 | } | ||
1831 | |||
1832 | if (num_clips && clips_ptr) { | ||
1833 | clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); | ||
1834 | if (!clips) { | ||
1835 | ret = -ENOMEM; | ||
1836 | goto out_err1; | ||
1837 | } | ||
1838 | |||
1839 | ret = copy_from_user(clips, clips_ptr, | ||
1840 | num_clips * sizeof(*clips)); | ||
1841 | if (ret) | ||
1842 | goto out_err2; | ||
1843 | } | ||
1844 | |||
1845 | if (fb->funcs->dirty) { | ||
1846 | ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips); | ||
1847 | } else { | ||
1848 | ret = -ENOSYS; | ||
1849 | goto out_err2; | ||
1850 | } | ||
1851 | |||
1852 | out_err2: | ||
1853 | kfree(clips); | ||
1854 | out_err1: | ||
1855 | mutex_unlock(&dev->mode_config.mutex); | ||
1856 | return ret; | ||
1857 | } | ||
1858 | |||
1859 | |||
1756 | /** | 1860 | /** |
1757 | * drm_fb_release - remove and free the FBs on this file | 1861 | * drm_fb_release - remove and free the FBs on this file |
1758 | * @filp: file * from the ioctl | 1862 | * @filp: file * from the ioctl |
@@ -2478,3 +2582,72 @@ out: | |||
2478 | mutex_unlock(&dev->mode_config.mutex); | 2582 | mutex_unlock(&dev->mode_config.mutex); |
2479 | return ret; | 2583 | return ret; |
2480 | } | 2584 | } |
2585 | |||
2586 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
2587 | void *data, struct drm_file *file_priv) | ||
2588 | { | ||
2589 | struct drm_mode_crtc_page_flip *page_flip = data; | ||
2590 | struct drm_mode_object *obj; | ||
2591 | struct drm_crtc *crtc; | ||
2592 | struct drm_framebuffer *fb; | ||
2593 | struct drm_pending_vblank_event *e = NULL; | ||
2594 | unsigned long flags; | ||
2595 | int ret = -EINVAL; | ||
2596 | |||
2597 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | ||
2598 | page_flip->reserved != 0) | ||
2599 | return -EINVAL; | ||
2600 | |||
2601 | mutex_lock(&dev->mode_config.mutex); | ||
2602 | obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
2603 | if (!obj) | ||
2604 | goto out; | ||
2605 | crtc = obj_to_crtc(obj); | ||
2606 | |||
2607 | if (crtc->funcs->page_flip == NULL) | ||
2608 | goto out; | ||
2609 | |||
2610 | obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); | ||
2611 | if (!obj) | ||
2612 | goto out; | ||
2613 | fb = obj_to_fb(obj); | ||
2614 | |||
2615 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
2616 | ret = -ENOMEM; | ||
2617 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2618 | if (file_priv->event_space < sizeof e->event) { | ||
2619 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2620 | goto out; | ||
2621 | } | ||
2622 | file_priv->event_space -= sizeof e->event; | ||
2623 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2624 | |||
2625 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
2626 | if (e == NULL) { | ||
2627 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2628 | file_priv->event_space += sizeof e->event; | ||
2629 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2630 | goto out; | ||
2631 | } | ||
2632 | |||
2633 | e->event.base.type = DRM_EVENT_VBLANK; | ||
2634 | e->event.base.length = sizeof e->event; | ||
2635 | e->event.user_data = page_flip->user_data; | ||
2636 | e->base.event = &e->event.base; | ||
2637 | e->base.file_priv = file_priv; | ||
2638 | e->base.destroy = | ||
2639 | (void (*) (struct drm_pending_event *)) kfree; | ||
2640 | } | ||
2641 | |||
2642 | ret = crtc->funcs->page_flip(crtc, fb, e); | ||
2643 | if (ret) { | ||
2644 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2645 | file_priv->event_space += sizeof e->event; | ||
2646 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2647 | kfree(e); | ||
2648 | } | ||
2649 | |||
2650 | out: | ||
2651 | mutex_unlock(&dev->mode_config.mutex); | ||
2652 | return ret; | ||
2653 | } | ||