15718399fSFrançois Tigeot /* 25718399fSFrançois Tigeot * Copyright (c) 2006-2008 Intel Corporation 35718399fSFrançois Tigeot * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 45718399fSFrançois Tigeot * Copyright (c) 2008 Red Hat Inc. 55718399fSFrançois Tigeot * 65718399fSFrançois Tigeot * DRM core CRTC related functions 75718399fSFrançois Tigeot * 85718399fSFrançois Tigeot * Permission to use, copy, modify, distribute, and sell this software and its 95718399fSFrançois Tigeot * documentation for any purpose is hereby granted without fee, provided that 105718399fSFrançois Tigeot * the above copyright notice appear in all copies and that both that copyright 115718399fSFrançois Tigeot * notice and this permission notice appear in supporting documentation, and 125718399fSFrançois Tigeot * that the name of the copyright holders not be used in advertising or 135718399fSFrançois Tigeot * publicity pertaining to distribution of the software without specific, 145718399fSFrançois Tigeot * written prior permission. The copyright holders make no representations 155718399fSFrançois Tigeot * about the suitability of this software for any purpose. It is provided "as 165718399fSFrançois Tigeot * is" without express or implied warranty. 175718399fSFrançois Tigeot * 185718399fSFrançois Tigeot * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 195718399fSFrançois Tigeot * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 205718399fSFrançois Tigeot * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 215718399fSFrançois Tigeot * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 225718399fSFrançois Tigeot * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 235718399fSFrançois Tigeot * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 245718399fSFrançois Tigeot * OF THIS SOFTWARE. 255718399fSFrançois Tigeot * 265718399fSFrançois Tigeot * Authors: 275718399fSFrançois Tigeot * Keith Packard 285718399fSFrançois Tigeot * Eric Anholt <eric@anholt.net> 295718399fSFrançois Tigeot * Dave Airlie <airlied@linux.ie> 305718399fSFrançois Tigeot * Jesse Barnes <jesse.barnes@intel.com> 315718399fSFrançois Tigeot * 325718399fSFrançois Tigeot * $FreeBSD: src/sys/dev/drm2/drm_crtc.c,v 1.1 2012/05/22 11:07:44 kib Exp $ 335718399fSFrançois Tigeot */ 345718399fSFrançois Tigeot 3518e26a6dSFrançois Tigeot #include <drm/drmP.h> 3618e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3718e26a6dSFrançois Tigeot #include <drm/drm_edid.h> 385718399fSFrançois Tigeot #include <sys/limits.h> 395718399fSFrançois Tigeot 405718399fSFrançois Tigeot /* Avoid boilerplate. I'm tired of typing. */ 415718399fSFrançois Tigeot #define DRM_ENUM_NAME_FN(fnname, list) \ 425718399fSFrançois Tigeot char *fnname(int val) \ 435718399fSFrançois Tigeot { \ 445718399fSFrançois Tigeot int i; \ 455718399fSFrançois Tigeot for (i = 0; i < DRM_ARRAY_SIZE(list); i++) { \ 465718399fSFrançois Tigeot if (list[i].type == val) \ 475718399fSFrançois Tigeot return list[i].name; \ 485718399fSFrançois Tigeot } \ 495718399fSFrançois Tigeot return "(unknown)"; \ 505718399fSFrançois Tigeot } 515718399fSFrançois Tigeot 525718399fSFrançois Tigeot /* 535718399fSFrançois Tigeot * Global properties 545718399fSFrançois Tigeot */ 555718399fSFrançois Tigeot static struct drm_prop_enum_list drm_dpms_enum_list[] = 565718399fSFrançois Tigeot { { DRM_MODE_DPMS_ON, "On" }, 575718399fSFrançois Tigeot { DRM_MODE_DPMS_STANDBY, "Standby" }, 585718399fSFrançois Tigeot { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 595718399fSFrançois Tigeot { DRM_MODE_DPMS_OFF, "Off" } 605718399fSFrançois Tigeot }; 615718399fSFrançois Tigeot 625718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 635718399fSFrançois Tigeot 645718399fSFrançois Tigeot /* 655718399fSFrançois Tigeot * Optional properties 665718399fSFrançois Tigeot */ 675718399fSFrançois Tigeot static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = 685718399fSFrançois Tigeot { 695718399fSFrançois Tigeot { DRM_MODE_SCALE_NONE, "None" }, 705718399fSFrançois Tigeot { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 715718399fSFrançois Tigeot { DRM_MODE_SCALE_CENTER, "Center" }, 725718399fSFrançois Tigeot { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 735718399fSFrançois Tigeot }; 745718399fSFrançois Tigeot 755718399fSFrançois Tigeot static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = 765718399fSFrançois Tigeot { 775718399fSFrançois Tigeot { DRM_MODE_DITHERING_OFF, "Off" }, 785718399fSFrançois Tigeot { DRM_MODE_DITHERING_ON, "On" }, 795718399fSFrançois Tigeot { DRM_MODE_DITHERING_AUTO, "Automatic" }, 805718399fSFrançois Tigeot }; 815718399fSFrançois Tigeot 825718399fSFrançois Tigeot /* 835718399fSFrançois Tigeot * Non-global properties, but "required" for certain connectors. 845718399fSFrançois Tigeot */ 855718399fSFrançois Tigeot static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = 865718399fSFrançois Tigeot { 875718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 885718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 895718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 905718399fSFrançois Tigeot }; 915718399fSFrançois Tigeot 925718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 935718399fSFrançois Tigeot 945718399fSFrançois Tigeot static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = 955718399fSFrançois Tigeot { 965718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 975718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 985718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 995718399fSFrançois Tigeot }; 1005718399fSFrançois Tigeot 1015718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 1025718399fSFrançois Tigeot drm_dvi_i_subconnector_enum_list) 1035718399fSFrançois Tigeot 1045718399fSFrançois Tigeot static struct drm_prop_enum_list drm_tv_select_enum_list[] = 1055718399fSFrançois Tigeot { 1065718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 1075718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 1085718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 1095718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 1105718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 1115718399fSFrançois Tigeot }; 1125718399fSFrançois Tigeot 1135718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 1145718399fSFrançois Tigeot 1155718399fSFrançois Tigeot static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = 1165718399fSFrançois Tigeot { 1175718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 1185718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 1195718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 1205718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 1215718399fSFrançois Tigeot { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 1225718399fSFrançois Tigeot }; 1235718399fSFrançois Tigeot 1245718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 1255718399fSFrançois Tigeot drm_tv_subconnector_enum_list) 1265718399fSFrançois Tigeot 1275718399fSFrançois Tigeot static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 1285718399fSFrançois Tigeot { DRM_MODE_DIRTY_OFF, "Off" }, 1295718399fSFrançois Tigeot { DRM_MODE_DIRTY_ON, "On" }, 1305718399fSFrançois Tigeot { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 1315718399fSFrançois Tigeot }; 1325718399fSFrançois Tigeot 1335718399fSFrançois Tigeot DRM_ENUM_NAME_FN(drm_get_dirty_info_name, 1345718399fSFrançois Tigeot drm_dirty_info_enum_list) 1355718399fSFrançois Tigeot 1365718399fSFrançois Tigeot struct drm_conn_prop_enum_list { 1375718399fSFrançois Tigeot int type; 1385718399fSFrançois Tigeot char *name; 1395718399fSFrançois Tigeot int count; 1405718399fSFrançois Tigeot }; 1415718399fSFrançois Tigeot 1425718399fSFrançois Tigeot /* 1435718399fSFrançois Tigeot * Connector and encoder types. 1445718399fSFrançois Tigeot */ 1455718399fSFrançois Tigeot static struct drm_conn_prop_enum_list drm_connector_enum_list[] = 1465718399fSFrançois Tigeot { { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 }, 1475718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_VGA, "VGA", 0 }, 1485718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 }, 1495718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 }, 1505718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 }, 1515718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_Composite, "Composite", 0 }, 1525718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 }, 1535718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 }, 1545718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_Component, "Component", 0 }, 1555718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 }, 1565718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 }, 1575718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 }, 1585718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, 1595718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_TV, "TV", 0 }, 1605718399fSFrançois Tigeot { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, 1615718399fSFrançois Tigeot }; 1625718399fSFrançois Tigeot 1635718399fSFrançois Tigeot static struct drm_prop_enum_list drm_encoder_enum_list[] = 1645718399fSFrançois Tigeot { { DRM_MODE_ENCODER_NONE, "None" }, 1655718399fSFrançois Tigeot { DRM_MODE_ENCODER_DAC, "DAC" }, 1665718399fSFrançois Tigeot { DRM_MODE_ENCODER_TMDS, "TMDS" }, 1675718399fSFrançois Tigeot { DRM_MODE_ENCODER_LVDS, "LVDS" }, 1685718399fSFrançois Tigeot { DRM_MODE_ENCODER_TVDAC, "TV" }, 1695718399fSFrançois Tigeot }; 1705718399fSFrançois Tigeot 1716f486c69SFrançois Tigeot static void drm_property_destroy_blob(struct drm_device *dev, 1726f486c69SFrançois Tigeot struct drm_property_blob *blob); 1736f486c69SFrançois Tigeot 1745718399fSFrançois Tigeot char *drm_get_encoder_name(struct drm_encoder *encoder) 1755718399fSFrançois Tigeot { 1765718399fSFrançois Tigeot static char buf[32]; 1775718399fSFrançois Tigeot 1785718399fSFrançois Tigeot ksnprintf(buf, 32, "%s-%d", 1795718399fSFrançois Tigeot drm_encoder_enum_list[encoder->encoder_type].name, 1805718399fSFrançois Tigeot encoder->base.id); 1815718399fSFrançois Tigeot return buf; 1825718399fSFrançois Tigeot } 1835718399fSFrançois Tigeot 1845718399fSFrançois Tigeot char *drm_get_connector_name(struct drm_connector *connector) 1855718399fSFrançois Tigeot { 1865718399fSFrançois Tigeot static char buf[32]; 1875718399fSFrançois Tigeot 1885718399fSFrançois Tigeot ksnprintf(buf, 32, "%s-%d", 1895718399fSFrançois Tigeot drm_connector_enum_list[connector->connector_type].name, 1905718399fSFrançois Tigeot connector->connector_type_id); 1915718399fSFrançois Tigeot return buf; 1925718399fSFrançois Tigeot } 1935718399fSFrançois Tigeot 1945718399fSFrançois Tigeot char *drm_get_connector_status_name(enum drm_connector_status status) 1955718399fSFrançois Tigeot { 1965718399fSFrançois Tigeot if (status == connector_status_connected) 1975718399fSFrançois Tigeot return "connected"; 1985718399fSFrançois Tigeot else if (status == connector_status_disconnected) 1995718399fSFrançois Tigeot return "disconnected"; 2005718399fSFrançois Tigeot else 2015718399fSFrançois Tigeot return "unknown"; 2025718399fSFrançois Tigeot } 2035718399fSFrançois Tigeot 2045718399fSFrançois Tigeot /** 2055718399fSFrançois Tigeot * drm_mode_object_get - allocate a new identifier 2065718399fSFrançois Tigeot * @dev: DRM device 2075718399fSFrançois Tigeot * @ptr: object pointer, used to generate unique ID 2085718399fSFrançois Tigeot * @type: object type 2095718399fSFrançois Tigeot * 2105718399fSFrançois Tigeot * LOCKING: 2115718399fSFrançois Tigeot * 2125718399fSFrançois Tigeot * Create a unique identifier based on @ptr in @dev's identifier space. Used 2135718399fSFrançois Tigeot * for tracking modes, CRTCs and connectors. 2145718399fSFrançois Tigeot * 2155718399fSFrançois Tigeot * RETURNS: 2165718399fSFrançois Tigeot * New unique (relative to other objects in @dev) integer identifier for the 2175718399fSFrançois Tigeot * object. 2185718399fSFrançois Tigeot */ 2195718399fSFrançois Tigeot static int drm_mode_object_get(struct drm_device *dev, 2205718399fSFrançois Tigeot struct drm_mode_object *obj, uint32_t obj_type) 2215718399fSFrançois Tigeot { 222aea8bdbdSFrançois Tigeot int new_id = 0; 2235718399fSFrançois Tigeot int ret; 2245718399fSFrançois Tigeot 225aea8bdbdSFrançois Tigeot again: 226*c824b4f9SFrançois Tigeot if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { 227aea8bdbdSFrançois Tigeot DRM_ERROR("Ran out memory getting a mode number\n"); 228aea8bdbdSFrançois Tigeot return -ENOMEM; 229aea8bdbdSFrançois Tigeot } 230aea8bdbdSFrançois Tigeot 231aea8bdbdSFrançois Tigeot spin_lock(&dev->mode_config.idr_mutex); 232aea8bdbdSFrançois Tigeot ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); 233aea8bdbdSFrançois Tigeot spin_unlock(&dev->mode_config.idr_mutex); 234aea8bdbdSFrançois Tigeot if (ret == -EAGAIN) 235aea8bdbdSFrançois Tigeot goto again; 236aea8bdbdSFrançois Tigeot else if (ret) 237aea8bdbdSFrançois Tigeot return ret; 2385718399fSFrançois Tigeot 2395718399fSFrançois Tigeot obj->id = new_id; 2405718399fSFrançois Tigeot obj->type = obj_type; 2415718399fSFrançois Tigeot return 0; 2425718399fSFrançois Tigeot } 2435718399fSFrançois Tigeot 2445718399fSFrançois Tigeot /** 2455718399fSFrançois Tigeot * drm_mode_object_put - free an identifer 2465718399fSFrançois Tigeot * @dev: DRM device 2475718399fSFrançois Tigeot * @id: ID to free 2485718399fSFrançois Tigeot * 2495718399fSFrançois Tigeot * LOCKING: 2505718399fSFrançois Tigeot * Caller must hold DRM mode_config lock. 2515718399fSFrançois Tigeot * 2525718399fSFrançois Tigeot * Free @id from @dev's unique identifier pool. 2535718399fSFrançois Tigeot */ 2545718399fSFrançois Tigeot static void drm_mode_object_put(struct drm_device *dev, 2555718399fSFrançois Tigeot struct drm_mode_object *object) 2565718399fSFrançois Tigeot { 257aea8bdbdSFrançois Tigeot spin_lock(&dev->mode_config.idr_mutex); 258aea8bdbdSFrançois Tigeot idr_remove(&dev->mode_config.crtc_idr, object->id); 259aea8bdbdSFrançois Tigeot spin_unlock(&dev->mode_config.idr_mutex); 2605718399fSFrançois Tigeot } 2615718399fSFrançois Tigeot 2625718399fSFrançois Tigeot struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 2635718399fSFrançois Tigeot uint32_t id, uint32_t type) 2645718399fSFrançois Tigeot { 265aea8bdbdSFrançois Tigeot struct drm_mode_object *obj = NULL; 2665718399fSFrançois Tigeot 267aea8bdbdSFrançois Tigeot spin_lock(&dev->mode_config.idr_mutex); 268aea8bdbdSFrançois Tigeot obj = idr_find(&dev->mode_config.crtc_idr, id); 2695718399fSFrançois Tigeot if (!obj || (obj->type != type) || (obj->id != id)) 2705718399fSFrançois Tigeot obj = NULL; 271aea8bdbdSFrançois Tigeot spin_unlock(&dev->mode_config.idr_mutex); 2725718399fSFrançois Tigeot 2735718399fSFrançois Tigeot return obj; 2745718399fSFrançois Tigeot } 2755718399fSFrançois Tigeot 2765718399fSFrançois Tigeot /** 2775718399fSFrançois Tigeot * drm_framebuffer_init - initialize a framebuffer 2785718399fSFrançois Tigeot * @dev: DRM device 2795718399fSFrançois Tigeot * 2805718399fSFrançois Tigeot * LOCKING: 2815718399fSFrançois Tigeot * Caller must hold mode config lock. 2825718399fSFrançois Tigeot * 2835718399fSFrançois Tigeot * Allocates an ID for the framebuffer's parent mode object, sets its mode 2845718399fSFrançois Tigeot * functions & device file and adds it to the master fd list. 2855718399fSFrançois Tigeot * 2865718399fSFrançois Tigeot * RETURNS: 2875718399fSFrançois Tigeot * Zero on success, error code on failure. 2885718399fSFrançois Tigeot */ 2895718399fSFrançois Tigeot int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 2905718399fSFrançois Tigeot const struct drm_framebuffer_funcs *funcs) 2915718399fSFrançois Tigeot { 2925718399fSFrançois Tigeot int ret; 2935718399fSFrançois Tigeot 2945718399fSFrançois Tigeot DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 2955718399fSFrançois Tigeot 2965718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 2975718399fSFrançois Tigeot if (ret) 2985718399fSFrançois Tigeot return ret; 2995718399fSFrançois Tigeot 3005718399fSFrançois Tigeot fb->dev = dev; 3015718399fSFrançois Tigeot fb->funcs = funcs; 3025718399fSFrançois Tigeot dev->mode_config.num_fb++; 3035718399fSFrançois Tigeot list_add(&fb->head, &dev->mode_config.fb_list); 3045718399fSFrançois Tigeot 3055718399fSFrançois Tigeot return 0; 3065718399fSFrançois Tigeot } 3075718399fSFrançois Tigeot 3085718399fSFrançois Tigeot /** 3095718399fSFrançois Tigeot * drm_framebuffer_cleanup - remove a framebuffer object 3105718399fSFrançois Tigeot * @fb: framebuffer to remove 3115718399fSFrançois Tigeot * 3125718399fSFrançois Tigeot * LOCKING: 3135718399fSFrançois Tigeot * Caller must hold mode config lock. 3145718399fSFrançois Tigeot * 3155718399fSFrançois Tigeot * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes 3165718399fSFrançois Tigeot * it, setting it to NULL. 3175718399fSFrançois Tigeot */ 3185718399fSFrançois Tigeot void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 3195718399fSFrançois Tigeot { 3205718399fSFrançois Tigeot struct drm_device *dev = fb->dev; 3215718399fSFrançois Tigeot struct drm_crtc *crtc; 3225718399fSFrançois Tigeot struct drm_plane *plane; 3235718399fSFrançois Tigeot struct drm_mode_set set; 3245718399fSFrançois Tigeot int ret; 3255718399fSFrançois Tigeot 3265718399fSFrançois Tigeot DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 3275718399fSFrançois Tigeot 3285718399fSFrançois Tigeot /* remove from any CRTC */ 3295718399fSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 3305718399fSFrançois Tigeot if (crtc->fb == fb) { 3315718399fSFrançois Tigeot /* should turn off the crtc */ 3325718399fSFrançois Tigeot memset(&set, 0, sizeof(struct drm_mode_set)); 3335718399fSFrançois Tigeot set.crtc = crtc; 3345718399fSFrançois Tigeot set.fb = NULL; 3355718399fSFrançois Tigeot ret = crtc->funcs->set_config(&set); 3365718399fSFrançois Tigeot if (ret) 3375718399fSFrançois Tigeot DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 3385718399fSFrançois Tigeot } 3395718399fSFrançois Tigeot } 3405718399fSFrançois Tigeot 3415718399fSFrançois Tigeot list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 3425718399fSFrançois Tigeot if (plane->fb == fb) { 3435718399fSFrançois Tigeot /* should turn off the crtc */ 3445718399fSFrançois Tigeot ret = plane->funcs->disable_plane(plane); 3455718399fSFrançois Tigeot if (ret) 3465718399fSFrançois Tigeot DRM_ERROR("failed to disable plane with busy fb\n"); 3475718399fSFrançois Tigeot /* disconnect the plane from the fb and crtc: */ 3485718399fSFrançois Tigeot plane->fb = NULL; 3495718399fSFrançois Tigeot plane->crtc = NULL; 3505718399fSFrançois Tigeot } 3515718399fSFrançois Tigeot } 3525718399fSFrançois Tigeot 3535718399fSFrançois Tigeot drm_mode_object_put(dev, &fb->base); 3545718399fSFrançois Tigeot list_del(&fb->head); 3555718399fSFrançois Tigeot dev->mode_config.num_fb--; 3565718399fSFrançois Tigeot } 3575718399fSFrançois Tigeot 3585718399fSFrançois Tigeot /** 3595718399fSFrançois Tigeot * drm_crtc_init - Initialise a new CRTC object 3605718399fSFrançois Tigeot * @dev: DRM device 3615718399fSFrançois Tigeot * @crtc: CRTC object to init 3625718399fSFrançois Tigeot * @funcs: callbacks for the new CRTC 3635718399fSFrançois Tigeot * 3645718399fSFrançois Tigeot * LOCKING: 3655718399fSFrançois Tigeot * Caller must hold mode config lock. 3665718399fSFrançois Tigeot * 3675718399fSFrançois Tigeot * Inits a new object created as base part of an driver crtc object. 3685718399fSFrançois Tigeot * 3695718399fSFrançois Tigeot * RETURNS: 3705718399fSFrançois Tigeot * Zero on success, error code on failure. 3715718399fSFrançois Tigeot */ 3725718399fSFrançois Tigeot int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 3735718399fSFrançois Tigeot const struct drm_crtc_funcs *funcs) 3745718399fSFrançois Tigeot { 3755718399fSFrançois Tigeot int ret; 3765718399fSFrançois Tigeot 3775718399fSFrançois Tigeot crtc->dev = dev; 3785718399fSFrançois Tigeot crtc->funcs = funcs; 3795718399fSFrançois Tigeot 3805718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 3815718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 3825718399fSFrançois Tigeot if (ret) 3835718399fSFrançois Tigeot goto out; 3845718399fSFrançois Tigeot 3855718399fSFrançois Tigeot list_add_tail(&crtc->head, &dev->mode_config.crtc_list); 3865718399fSFrançois Tigeot dev->mode_config.num_crtc++; 3875718399fSFrançois Tigeot out: 3885718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 3895718399fSFrançois Tigeot 3905718399fSFrançois Tigeot return ret; 3915718399fSFrançois Tigeot } 3925718399fSFrançois Tigeot 3935718399fSFrançois Tigeot /** 3945718399fSFrançois Tigeot * drm_crtc_cleanup - Cleans up the core crtc usage. 3955718399fSFrançois Tigeot * @crtc: CRTC to cleanup 3965718399fSFrançois Tigeot * 3975718399fSFrançois Tigeot * LOCKING: 3985718399fSFrançois Tigeot * Caller must hold mode config lock. 3995718399fSFrançois Tigeot * 4005718399fSFrançois Tigeot * Cleanup @crtc. Removes from drm modesetting space 4015718399fSFrançois Tigeot * does NOT free object, caller does that. 4025718399fSFrançois Tigeot */ 4035718399fSFrançois Tigeot void drm_crtc_cleanup(struct drm_crtc *crtc) 4045718399fSFrançois Tigeot { 4055718399fSFrançois Tigeot struct drm_device *dev = crtc->dev; 4065718399fSFrançois Tigeot 4075718399fSFrançois Tigeot DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 4085718399fSFrançois Tigeot 4095718399fSFrançois Tigeot if (crtc->gamma_store) { 4105718399fSFrançois Tigeot drm_free(crtc->gamma_store, DRM_MEM_KMS); 4115718399fSFrançois Tigeot crtc->gamma_store = NULL; 4125718399fSFrançois Tigeot } 4135718399fSFrançois Tigeot 4145718399fSFrançois Tigeot drm_mode_object_put(dev, &crtc->base); 4155718399fSFrançois Tigeot list_del(&crtc->head); 4165718399fSFrançois Tigeot dev->mode_config.num_crtc--; 4175718399fSFrançois Tigeot } 4185718399fSFrançois Tigeot 4195718399fSFrançois Tigeot /** 4205718399fSFrançois Tigeot * drm_mode_probed_add - add a mode to a connector's probed mode list 4215718399fSFrançois Tigeot * @connector: connector the new mode 4225718399fSFrançois Tigeot * @mode: mode data 4235718399fSFrançois Tigeot * 4245718399fSFrançois Tigeot * LOCKING: 4255718399fSFrançois Tigeot * Caller must hold mode config lock. 4265718399fSFrançois Tigeot * 4275718399fSFrançois Tigeot * Add @mode to @connector's mode list for later use. 4285718399fSFrançois Tigeot */ 4295718399fSFrançois Tigeot void drm_mode_probed_add(struct drm_connector *connector, 4305718399fSFrançois Tigeot struct drm_display_mode *mode) 4315718399fSFrançois Tigeot { 4325718399fSFrançois Tigeot 4335718399fSFrançois Tigeot DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); 4345718399fSFrançois Tigeot 4355718399fSFrançois Tigeot list_add(&mode->head, &connector->probed_modes); 4365718399fSFrançois Tigeot } 4375718399fSFrançois Tigeot 4385718399fSFrançois Tigeot /** 4395718399fSFrançois Tigeot * drm_mode_remove - remove and free a mode 4405718399fSFrançois Tigeot * @connector: connector list to modify 4415718399fSFrançois Tigeot * @mode: mode to remove 4425718399fSFrançois Tigeot * 4435718399fSFrançois Tigeot * LOCKING: 4445718399fSFrançois Tigeot * Caller must hold mode config lock. 4455718399fSFrançois Tigeot * 4465718399fSFrançois Tigeot * Remove @mode from @connector's mode list, then free it. 4475718399fSFrançois Tigeot */ 4485718399fSFrançois Tigeot void drm_mode_remove(struct drm_connector *connector, 4495718399fSFrançois Tigeot struct drm_display_mode *mode) 4505718399fSFrançois Tigeot { 4515718399fSFrançois Tigeot 4525718399fSFrançois Tigeot DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); 4535718399fSFrançois Tigeot 4545718399fSFrançois Tigeot list_del(&mode->head); 4555718399fSFrançois Tigeot drm_mode_destroy(connector->dev, mode); 4565718399fSFrançois Tigeot } 4575718399fSFrançois Tigeot 4585718399fSFrançois Tigeot /** 4595718399fSFrançois Tigeot * drm_connector_init - Init a preallocated connector 4605718399fSFrançois Tigeot * @dev: DRM device 4615718399fSFrançois Tigeot * @connector: the connector to init 4625718399fSFrançois Tigeot * @funcs: callbacks for this connector 4635718399fSFrançois Tigeot * @name: user visible name of the connector 4645718399fSFrançois Tigeot * 4655718399fSFrançois Tigeot * LOCKING: 4665718399fSFrançois Tigeot * Takes mode config lock. 4675718399fSFrançois Tigeot * 4685718399fSFrançois Tigeot * Initialises a preallocated connector. Connectors should be 4695718399fSFrançois Tigeot * subclassed as part of driver connector objects. 4705718399fSFrançois Tigeot * 4715718399fSFrançois Tigeot * RETURNS: 4725718399fSFrançois Tigeot * Zero on success, error code on failure. 4735718399fSFrançois Tigeot */ 4745718399fSFrançois Tigeot int drm_connector_init(struct drm_device *dev, 4755718399fSFrançois Tigeot struct drm_connector *connector, 4765718399fSFrançois Tigeot const struct drm_connector_funcs *funcs, 4775718399fSFrançois Tigeot int connector_type) 4785718399fSFrançois Tigeot { 4795718399fSFrançois Tigeot int ret; 4805718399fSFrançois Tigeot 4815718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 4825718399fSFrançois Tigeot 4835718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); 4845718399fSFrançois Tigeot if (ret) 4855718399fSFrançois Tigeot goto out; 4865718399fSFrançois Tigeot 4875718399fSFrançois Tigeot connector->dev = dev; 4885718399fSFrançois Tigeot connector->funcs = funcs; 4895718399fSFrançois Tigeot connector->connector_type = connector_type; 4905718399fSFrançois Tigeot connector->connector_type_id = 4915718399fSFrançois Tigeot ++drm_connector_enum_list[connector_type].count; /* TODO */ 4925718399fSFrançois Tigeot INIT_LIST_HEAD(&connector->user_modes); 4935718399fSFrançois Tigeot INIT_LIST_HEAD(&connector->probed_modes); 4945718399fSFrançois Tigeot INIT_LIST_HEAD(&connector->modes); 4955718399fSFrançois Tigeot connector->edid_blob_ptr = NULL; 4965718399fSFrançois Tigeot 4975718399fSFrançois Tigeot list_add_tail(&connector->head, &dev->mode_config.connector_list); 4985718399fSFrançois Tigeot dev->mode_config.num_connector++; 4995718399fSFrançois Tigeot 5005718399fSFrançois Tigeot drm_connector_attach_property(connector, 5015718399fSFrançois Tigeot dev->mode_config.edid_property, 0); 5025718399fSFrançois Tigeot 5035718399fSFrançois Tigeot drm_connector_attach_property(connector, 5045718399fSFrançois Tigeot dev->mode_config.dpms_property, 0); 5055718399fSFrançois Tigeot 5065718399fSFrançois Tigeot out: 5075718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 5085718399fSFrançois Tigeot 5095718399fSFrançois Tigeot return ret; 5105718399fSFrançois Tigeot } 5115718399fSFrançois Tigeot 5125718399fSFrançois Tigeot /** 5135718399fSFrançois Tigeot * drm_connector_cleanup - cleans up an initialised connector 5145718399fSFrançois Tigeot * @connector: connector to cleanup 5155718399fSFrançois Tigeot * 5165718399fSFrançois Tigeot * LOCKING: 5175718399fSFrançois Tigeot * Takes mode config lock. 5185718399fSFrançois Tigeot * 5195718399fSFrançois Tigeot * Cleans up the connector but doesn't free the object. 5205718399fSFrançois Tigeot */ 5215718399fSFrançois Tigeot void drm_connector_cleanup(struct drm_connector *connector) 5225718399fSFrançois Tigeot { 5235718399fSFrançois Tigeot struct drm_device *dev = connector->dev; 5245718399fSFrançois Tigeot struct drm_display_mode *mode, *t; 5255718399fSFrançois Tigeot 5265718399fSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 5275718399fSFrançois Tigeot drm_mode_remove(connector, mode); 5285718399fSFrançois Tigeot 5295718399fSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->modes, head) 5305718399fSFrançois Tigeot drm_mode_remove(connector, mode); 5315718399fSFrançois Tigeot 5325718399fSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->user_modes, head) 5335718399fSFrançois Tigeot drm_mode_remove(connector, mode); 5345718399fSFrançois Tigeot 5355718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 5366f486c69SFrançois Tigeot if (connector->edid_blob_ptr) 5376f486c69SFrançois Tigeot drm_property_destroy_blob(dev, connector->edid_blob_ptr); 5385718399fSFrançois Tigeot drm_mode_object_put(dev, &connector->base); 5395718399fSFrançois Tigeot list_del(&connector->head); 5405718399fSFrançois Tigeot dev->mode_config.num_connector--; 5415718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 5425718399fSFrançois Tigeot } 5435718399fSFrançois Tigeot 5445718399fSFrançois Tigeot int drm_encoder_init(struct drm_device *dev, 5455718399fSFrançois Tigeot struct drm_encoder *encoder, 5465718399fSFrançois Tigeot const struct drm_encoder_funcs *funcs, 5475718399fSFrançois Tigeot int encoder_type) 5485718399fSFrançois Tigeot { 5495718399fSFrançois Tigeot int ret; 5505718399fSFrançois Tigeot 5515718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 5525718399fSFrançois Tigeot 5535718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 5545718399fSFrançois Tigeot if (ret) 5555718399fSFrançois Tigeot goto out; 5565718399fSFrançois Tigeot 5575718399fSFrançois Tigeot encoder->dev = dev; 5585718399fSFrançois Tigeot encoder->encoder_type = encoder_type; 5595718399fSFrançois Tigeot encoder->funcs = funcs; 5605718399fSFrançois Tigeot 5615718399fSFrançois Tigeot list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 5625718399fSFrançois Tigeot dev->mode_config.num_encoder++; 5635718399fSFrançois Tigeot 5645718399fSFrançois Tigeot out: 5655718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 5665718399fSFrançois Tigeot 5675718399fSFrançois Tigeot return ret; 5685718399fSFrançois Tigeot } 5695718399fSFrançois Tigeot 5705718399fSFrançois Tigeot void drm_encoder_cleanup(struct drm_encoder *encoder) 5715718399fSFrançois Tigeot { 5725718399fSFrançois Tigeot struct drm_device *dev = encoder->dev; 5735718399fSFrançois Tigeot 5745718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 5755718399fSFrançois Tigeot drm_mode_object_put(dev, &encoder->base); 5765718399fSFrançois Tigeot list_del(&encoder->head); 5775718399fSFrançois Tigeot dev->mode_config.num_encoder--; 5785718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 5795718399fSFrançois Tigeot } 5805718399fSFrançois Tigeot 5815718399fSFrançois Tigeot int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 5825718399fSFrançois Tigeot unsigned long possible_crtcs, 5835718399fSFrançois Tigeot const struct drm_plane_funcs *funcs, 5845718399fSFrançois Tigeot const uint32_t *formats, uint32_t format_count, 5855718399fSFrançois Tigeot bool priv) 5865718399fSFrançois Tigeot { 5875718399fSFrançois Tigeot int ret; 5885718399fSFrançois Tigeot 5895718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 5905718399fSFrançois Tigeot 5915718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 5925718399fSFrançois Tigeot if (ret) 5935718399fSFrançois Tigeot goto out; 5945718399fSFrançois Tigeot 5955718399fSFrançois Tigeot plane->dev = dev; 5965718399fSFrançois Tigeot plane->funcs = funcs; 5975718399fSFrançois Tigeot plane->format_types = kmalloc(sizeof(uint32_t) * format_count, 5985718399fSFrançois Tigeot DRM_MEM_KMS, M_WAITOK); 5995718399fSFrançois Tigeot 6005718399fSFrançois Tigeot memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 6015718399fSFrançois Tigeot plane->format_count = format_count; 6025718399fSFrançois Tigeot plane->possible_crtcs = possible_crtcs; 6035718399fSFrançois Tigeot 6045718399fSFrançois Tigeot /* private planes are not exposed to userspace, but depending on 6055718399fSFrançois Tigeot * display hardware, might be convenient to allow sharing programming 6065718399fSFrançois Tigeot * for the scanout engine with the crtc implementation. 6075718399fSFrançois Tigeot */ 6085718399fSFrançois Tigeot if (!priv) { 6095718399fSFrançois Tigeot list_add_tail(&plane->head, &dev->mode_config.plane_list); 6105718399fSFrançois Tigeot dev->mode_config.num_plane++; 6115718399fSFrançois Tigeot } else { 6125718399fSFrançois Tigeot INIT_LIST_HEAD(&plane->head); 6135718399fSFrançois Tigeot } 6145718399fSFrançois Tigeot 6155718399fSFrançois Tigeot out: 6165718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 6175718399fSFrançois Tigeot 6185718399fSFrançois Tigeot return ret; 6195718399fSFrançois Tigeot } 6205718399fSFrançois Tigeot 6215718399fSFrançois Tigeot void drm_plane_cleanup(struct drm_plane *plane) 6225718399fSFrançois Tigeot { 6235718399fSFrançois Tigeot struct drm_device *dev = plane->dev; 6245718399fSFrançois Tigeot 6255718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 6265718399fSFrançois Tigeot drm_free(plane->format_types, DRM_MEM_KMS); 6275718399fSFrançois Tigeot drm_mode_object_put(dev, &plane->base); 6285718399fSFrançois Tigeot /* if not added to a list, it must be a private plane */ 6295718399fSFrançois Tigeot if (!list_empty(&plane->head)) { 6305718399fSFrançois Tigeot list_del(&plane->head); 6315718399fSFrançois Tigeot dev->mode_config.num_plane--; 6325718399fSFrançois Tigeot } 6335718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 6345718399fSFrançois Tigeot } 6355718399fSFrançois Tigeot 6365718399fSFrançois Tigeot /** 6375718399fSFrançois Tigeot * drm_mode_create - create a new display mode 6385718399fSFrançois Tigeot * @dev: DRM device 6395718399fSFrançois Tigeot * 6405718399fSFrançois Tigeot * LOCKING: 6415718399fSFrançois Tigeot * Caller must hold DRM mode_config lock. 6425718399fSFrançois Tigeot * 6435718399fSFrançois Tigeot * Create a new drm_display_mode, give it an ID, and return it. 6445718399fSFrançois Tigeot * 6455718399fSFrançois Tigeot * RETURNS: 6465718399fSFrançois Tigeot * Pointer to new mode on success, NULL on error. 6475718399fSFrançois Tigeot */ 6485718399fSFrançois Tigeot struct drm_display_mode *drm_mode_create(struct drm_device *dev) 6495718399fSFrançois Tigeot { 6505718399fSFrançois Tigeot struct drm_display_mode *nmode; 6515718399fSFrançois Tigeot 6525718399fSFrançois Tigeot nmode = kmalloc(sizeof(struct drm_display_mode), DRM_MEM_KMS, 6535718399fSFrançois Tigeot M_WAITOK | M_ZERO); 6545718399fSFrançois Tigeot 6555718399fSFrançois Tigeot if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { 6565718399fSFrançois Tigeot drm_free(nmode, DRM_MEM_KMS); 6575718399fSFrançois Tigeot return (NULL); 6585718399fSFrançois Tigeot } 6595718399fSFrançois Tigeot return nmode; 6605718399fSFrançois Tigeot } 6615718399fSFrançois Tigeot 6625718399fSFrançois Tigeot /** 6635718399fSFrançois Tigeot * drm_mode_destroy - remove a mode 6645718399fSFrançois Tigeot * @dev: DRM device 6655718399fSFrançois Tigeot * @mode: mode to remove 6665718399fSFrançois Tigeot * 6675718399fSFrançois Tigeot * LOCKING: 6685718399fSFrançois Tigeot * Caller must hold mode config lock. 6695718399fSFrançois Tigeot * 6705718399fSFrançois Tigeot * Free @mode's unique identifier, then free it. 6715718399fSFrançois Tigeot */ 6725718399fSFrançois Tigeot void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) 6735718399fSFrançois Tigeot { 6745718399fSFrançois Tigeot if (!mode) 6755718399fSFrançois Tigeot return; 6765718399fSFrançois Tigeot 6775718399fSFrançois Tigeot drm_mode_object_put(dev, &mode->base); 6785718399fSFrançois Tigeot 6795718399fSFrançois Tigeot drm_free(mode, DRM_MEM_KMS); 6805718399fSFrançois Tigeot } 6815718399fSFrançois Tigeot 6825718399fSFrançois Tigeot static int drm_mode_create_standard_connector_properties(struct drm_device *dev) 6835718399fSFrançois Tigeot { 6845718399fSFrançois Tigeot struct drm_property *edid; 6855718399fSFrançois Tigeot struct drm_property *dpms; 6865718399fSFrançois Tigeot 6875718399fSFrançois Tigeot /* 6885718399fSFrançois Tigeot * Standard properties (apply to all connectors) 6895718399fSFrançois Tigeot */ 6905718399fSFrançois Tigeot edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | 6915718399fSFrançois Tigeot DRM_MODE_PROP_IMMUTABLE, 6925718399fSFrançois Tigeot "EDID", 0); 6935718399fSFrançois Tigeot dev->mode_config.edid_property = edid; 6945718399fSFrançois Tigeot 6955718399fSFrançois Tigeot dpms = drm_property_create_enum(dev, 0, 6965718399fSFrançois Tigeot "DPMS", drm_dpms_enum_list, 6975718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_dpms_enum_list)); 6985718399fSFrançois Tigeot dev->mode_config.dpms_property = dpms; 6995718399fSFrançois Tigeot 7005718399fSFrançois Tigeot return 0; 7015718399fSFrançois Tigeot } 7025718399fSFrançois Tigeot 7035718399fSFrançois Tigeot /** 7045718399fSFrançois Tigeot * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 7055718399fSFrançois Tigeot * @dev: DRM device 7065718399fSFrançois Tigeot * 7075718399fSFrançois Tigeot * Called by a driver the first time a DVI-I connector is made. 7085718399fSFrançois Tigeot */ 7095718399fSFrançois Tigeot int drm_mode_create_dvi_i_properties(struct drm_device *dev) 7105718399fSFrançois Tigeot { 7115718399fSFrançois Tigeot struct drm_property *dvi_i_selector; 7125718399fSFrançois Tigeot struct drm_property *dvi_i_subconnector; 7135718399fSFrançois Tigeot 7145718399fSFrançois Tigeot if (dev->mode_config.dvi_i_select_subconnector_property) 7155718399fSFrançois Tigeot return 0; 7165718399fSFrançois Tigeot 7175718399fSFrançois Tigeot dvi_i_selector = 7185718399fSFrançois Tigeot drm_property_create_enum(dev, 0, 7195718399fSFrançois Tigeot "select subconnector", 7205718399fSFrançois Tigeot drm_dvi_i_select_enum_list, 7215718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_dvi_i_select_enum_list)); 7225718399fSFrançois Tigeot dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 7235718399fSFrançois Tigeot 7245718399fSFrançois Tigeot dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 7255718399fSFrançois Tigeot "subconnector", 7265718399fSFrançois Tigeot drm_dvi_i_subconnector_enum_list, 7275718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 7285718399fSFrançois Tigeot dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 7295718399fSFrançois Tigeot 7305718399fSFrançois Tigeot return 0; 7315718399fSFrançois Tigeot } 7325718399fSFrançois Tigeot 7335718399fSFrançois Tigeot /** 7345718399fSFrançois Tigeot * drm_create_tv_properties - create TV specific connector properties 7355718399fSFrançois Tigeot * @dev: DRM device 7365718399fSFrançois Tigeot * @num_modes: number of different TV formats (modes) supported 7375718399fSFrançois Tigeot * @modes: array of pointers to strings containing name of each format 7385718399fSFrançois Tigeot * 7395718399fSFrançois Tigeot * Called by a driver's TV initialization routine, this function creates 7405718399fSFrançois Tigeot * the TV specific connector properties for a given device. Caller is 7415718399fSFrançois Tigeot * responsible for allocating a list of format names and passing them to 7425718399fSFrançois Tigeot * this routine. 7435718399fSFrançois Tigeot */ 7445718399fSFrançois Tigeot int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, 7455718399fSFrançois Tigeot char *modes[]) 7465718399fSFrançois Tigeot { 7475718399fSFrançois Tigeot struct drm_property *tv_selector; 7485718399fSFrançois Tigeot struct drm_property *tv_subconnector; 7495718399fSFrançois Tigeot int i; 7505718399fSFrançois Tigeot 7515718399fSFrançois Tigeot if (dev->mode_config.tv_select_subconnector_property) 7525718399fSFrançois Tigeot return 0; 7535718399fSFrançois Tigeot 7545718399fSFrançois Tigeot /* 7555718399fSFrançois Tigeot * Basic connector properties 7565718399fSFrançois Tigeot */ 7575718399fSFrançois Tigeot tv_selector = drm_property_create_enum(dev, 0, 7585718399fSFrançois Tigeot "select subconnector", 7595718399fSFrançois Tigeot drm_tv_select_enum_list, 7605718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_tv_select_enum_list)); 7615718399fSFrançois Tigeot dev->mode_config.tv_select_subconnector_property = tv_selector; 7625718399fSFrançois Tigeot 7635718399fSFrançois Tigeot tv_subconnector = 7645718399fSFrançois Tigeot drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 7655718399fSFrançois Tigeot "subconnector", 7665718399fSFrançois Tigeot drm_tv_subconnector_enum_list, 7675718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_tv_subconnector_enum_list)); 7685718399fSFrançois Tigeot dev->mode_config.tv_subconnector_property = tv_subconnector; 7695718399fSFrançois Tigeot 7705718399fSFrançois Tigeot /* 7715718399fSFrançois Tigeot * Other, TV specific properties: margins & TV modes. 7725718399fSFrançois Tigeot */ 7735718399fSFrançois Tigeot dev->mode_config.tv_left_margin_property = 7745718399fSFrançois Tigeot drm_property_create_range(dev, 0, "left margin", 0, 100); 7755718399fSFrançois Tigeot 7765718399fSFrançois Tigeot dev->mode_config.tv_right_margin_property = 7775718399fSFrançois Tigeot drm_property_create_range(dev, 0, "right margin", 0, 100); 7785718399fSFrançois Tigeot 7795718399fSFrançois Tigeot dev->mode_config.tv_top_margin_property = 7805718399fSFrançois Tigeot drm_property_create_range(dev, 0, "top margin", 0, 100); 7815718399fSFrançois Tigeot 7825718399fSFrançois Tigeot dev->mode_config.tv_bottom_margin_property = 7835718399fSFrançois Tigeot drm_property_create_range(dev, 0, "bottom margin", 0, 100); 7845718399fSFrançois Tigeot 7855718399fSFrançois Tigeot dev->mode_config.tv_mode_property = 7865718399fSFrançois Tigeot drm_property_create(dev, DRM_MODE_PROP_ENUM, 7875718399fSFrançois Tigeot "mode", num_modes); 7885718399fSFrançois Tigeot for (i = 0; i < num_modes; i++) 7895718399fSFrançois Tigeot drm_property_add_enum(dev->mode_config.tv_mode_property, i, 7905718399fSFrançois Tigeot i, modes[i]); 7915718399fSFrançois Tigeot 7925718399fSFrançois Tigeot dev->mode_config.tv_brightness_property = 7935718399fSFrançois Tigeot drm_property_create_range(dev, 0, "brightness", 0, 100); 7945718399fSFrançois Tigeot 7955718399fSFrançois Tigeot dev->mode_config.tv_contrast_property = 7965718399fSFrançois Tigeot drm_property_create_range(dev, 0, "contrast", 0, 100); 7975718399fSFrançois Tigeot 7985718399fSFrançois Tigeot dev->mode_config.tv_flicker_reduction_property = 7995718399fSFrançois Tigeot drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 8005718399fSFrançois Tigeot 8015718399fSFrançois Tigeot dev->mode_config.tv_overscan_property = 8025718399fSFrançois Tigeot drm_property_create_range(dev, 0, "overscan", 0, 100); 8035718399fSFrançois Tigeot 8045718399fSFrançois Tigeot dev->mode_config.tv_saturation_property = 8055718399fSFrançois Tigeot drm_property_create_range(dev, 0, "saturation", 0, 100); 8065718399fSFrançois Tigeot 8075718399fSFrançois Tigeot dev->mode_config.tv_hue_property = 8085718399fSFrançois Tigeot drm_property_create_range(dev, 0, "hue", 0, 100); 8095718399fSFrançois Tigeot 8105718399fSFrançois Tigeot return 0; 8115718399fSFrançois Tigeot } 8125718399fSFrançois Tigeot 8135718399fSFrançois Tigeot /** 8145718399fSFrançois Tigeot * drm_mode_create_scaling_mode_property - create scaling mode property 8155718399fSFrançois Tigeot * @dev: DRM device 8165718399fSFrançois Tigeot * 8175718399fSFrançois Tigeot * Called by a driver the first time it's needed, must be attached to desired 8185718399fSFrançois Tigeot * connectors. 8195718399fSFrançois Tigeot */ 8205718399fSFrançois Tigeot int drm_mode_create_scaling_mode_property(struct drm_device *dev) 8215718399fSFrançois Tigeot { 8225718399fSFrançois Tigeot struct drm_property *scaling_mode; 8235718399fSFrançois Tigeot 8245718399fSFrançois Tigeot if (dev->mode_config.scaling_mode_property) 8255718399fSFrançois Tigeot return 0; 8265718399fSFrançois Tigeot 8275718399fSFrançois Tigeot scaling_mode = 8285718399fSFrançois Tigeot drm_property_create_enum(dev, 0, "scaling mode", 8295718399fSFrançois Tigeot drm_scaling_mode_enum_list, 8305718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_scaling_mode_enum_list)); 8315718399fSFrançois Tigeot 8325718399fSFrançois Tigeot dev->mode_config.scaling_mode_property = scaling_mode; 8335718399fSFrançois Tigeot 8345718399fSFrançois Tigeot return 0; 8355718399fSFrançois Tigeot } 8365718399fSFrançois Tigeot 8375718399fSFrançois Tigeot /** 8385718399fSFrançois Tigeot * drm_mode_create_dithering_property - create dithering property 8395718399fSFrançois Tigeot * @dev: DRM device 8405718399fSFrançois Tigeot * 8415718399fSFrançois Tigeot * Called by a driver the first time it's needed, must be attached to desired 8425718399fSFrançois Tigeot * connectors. 8435718399fSFrançois Tigeot */ 8445718399fSFrançois Tigeot int drm_mode_create_dithering_property(struct drm_device *dev) 8455718399fSFrançois Tigeot { 8465718399fSFrançois Tigeot struct drm_property *dithering_mode; 8475718399fSFrançois Tigeot 8485718399fSFrançois Tigeot if (dev->mode_config.dithering_mode_property) 8495718399fSFrançois Tigeot return 0; 8505718399fSFrançois Tigeot 8515718399fSFrançois Tigeot dithering_mode = 8525718399fSFrançois Tigeot drm_property_create_enum(dev, 0, "dithering", 8535718399fSFrançois Tigeot drm_dithering_mode_enum_list, 8545718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_dithering_mode_enum_list)); 8555718399fSFrançois Tigeot dev->mode_config.dithering_mode_property = dithering_mode; 8565718399fSFrançois Tigeot 8575718399fSFrançois Tigeot return 0; 8585718399fSFrançois Tigeot } 8595718399fSFrançois Tigeot 8605718399fSFrançois Tigeot /** 8615718399fSFrançois Tigeot * drm_mode_create_dirty_property - create dirty property 8625718399fSFrançois Tigeot * @dev: DRM device 8635718399fSFrançois Tigeot * 8645718399fSFrançois Tigeot * Called by a driver the first time it's needed, must be attached to desired 8655718399fSFrançois Tigeot * connectors. 8665718399fSFrançois Tigeot */ 8675718399fSFrançois Tigeot int drm_mode_create_dirty_info_property(struct drm_device *dev) 8685718399fSFrançois Tigeot { 8695718399fSFrançois Tigeot struct drm_property *dirty_info; 8705718399fSFrançois Tigeot 8715718399fSFrançois Tigeot if (dev->mode_config.dirty_info_property) 8725718399fSFrançois Tigeot return 0; 8735718399fSFrançois Tigeot 8745718399fSFrançois Tigeot dirty_info = 8755718399fSFrançois Tigeot drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 8765718399fSFrançois Tigeot "dirty", 8775718399fSFrançois Tigeot drm_dirty_info_enum_list, 8785718399fSFrançois Tigeot DRM_ARRAY_SIZE(drm_dirty_info_enum_list)); 8795718399fSFrançois Tigeot dev->mode_config.dirty_info_property = dirty_info; 8805718399fSFrançois Tigeot 8815718399fSFrançois Tigeot return 0; 8825718399fSFrançois Tigeot } 8835718399fSFrançois Tigeot 8845718399fSFrançois Tigeot /** 8855718399fSFrançois Tigeot * drm_mode_config_init - initialize DRM mode_configuration structure 8865718399fSFrançois Tigeot * @dev: DRM device 8875718399fSFrançois Tigeot * 8885718399fSFrançois Tigeot * LOCKING: 8895718399fSFrançois Tigeot * None, should happen single threaded at init time. 8905718399fSFrançois Tigeot * 8915718399fSFrançois Tigeot * Initialize @dev's mode_config structure, used for tracking the graphics 8925718399fSFrançois Tigeot * configuration of @dev. 8935718399fSFrançois Tigeot */ 8945718399fSFrançois Tigeot void drm_mode_config_init(struct drm_device *dev) 8955718399fSFrançois Tigeot { 8965718399fSFrançois Tigeot lockinit(&dev->mode_config.lock, "kmslk", 0, LK_CANRECURSE); 897aea8bdbdSFrançois Tigeot spin_init(&dev->mode_config.idr_mutex); 8985718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.fb_list); 8995718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.crtc_list); 9005718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.connector_list); 9015718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.encoder_list); 9025718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.property_list); 9035718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 9045718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->mode_config.plane_list); 905aea8bdbdSFrançois Tigeot idr_init(&dev->mode_config.crtc_idr); 9065718399fSFrançois Tigeot 9075718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 9085718399fSFrançois Tigeot drm_mode_create_standard_connector_properties(dev); 9095718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 9105718399fSFrançois Tigeot 9115718399fSFrançois Tigeot /* Just to be sure */ 9125718399fSFrançois Tigeot dev->mode_config.num_fb = 0; 9135718399fSFrançois Tigeot dev->mode_config.num_connector = 0; 9145718399fSFrançois Tigeot dev->mode_config.num_crtc = 0; 9155718399fSFrançois Tigeot dev->mode_config.num_encoder = 0; 9165718399fSFrançois Tigeot } 9175718399fSFrançois Tigeot 9185718399fSFrançois Tigeot static int 9195718399fSFrançois Tigeot drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 9205718399fSFrançois Tigeot { 9215718399fSFrançois Tigeot uint32_t total_objects = 0; 9225718399fSFrançois Tigeot 9235718399fSFrançois Tigeot total_objects += dev->mode_config.num_crtc; 9245718399fSFrançois Tigeot total_objects += dev->mode_config.num_connector; 9255718399fSFrançois Tigeot total_objects += dev->mode_config.num_encoder; 9265718399fSFrançois Tigeot 9275718399fSFrançois Tigeot group->id_list = kmalloc(total_objects * sizeof(uint32_t), 9285718399fSFrançois Tigeot DRM_MEM_KMS, M_WAITOK | M_ZERO); 9295718399fSFrançois Tigeot 9305718399fSFrançois Tigeot group->num_crtcs = 0; 9315718399fSFrançois Tigeot group->num_connectors = 0; 9325718399fSFrançois Tigeot group->num_encoders = 0; 9335718399fSFrançois Tigeot return 0; 9345718399fSFrançois Tigeot } 9355718399fSFrançois Tigeot 9365718399fSFrançois Tigeot int drm_mode_group_init_legacy_group(struct drm_device *dev, 9375718399fSFrançois Tigeot struct drm_mode_group *group) 9385718399fSFrançois Tigeot { 9395718399fSFrançois Tigeot struct drm_crtc *crtc; 9405718399fSFrançois Tigeot struct drm_encoder *encoder; 9415718399fSFrançois Tigeot struct drm_connector *connector; 9425718399fSFrançois Tigeot int ret; 9435718399fSFrançois Tigeot 9445718399fSFrançois Tigeot if ((ret = drm_mode_group_init(dev, group))) 9455718399fSFrançois Tigeot return ret; 9465718399fSFrançois Tigeot 9475718399fSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 9485718399fSFrançois Tigeot group->id_list[group->num_crtcs++] = crtc->base.id; 9495718399fSFrançois Tigeot 9505718399fSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 9515718399fSFrançois Tigeot group->id_list[group->num_crtcs + group->num_encoders++] = 9525718399fSFrançois Tigeot encoder->base.id; 9535718399fSFrançois Tigeot 9545718399fSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) 9555718399fSFrançois Tigeot group->id_list[group->num_crtcs + group->num_encoders + 9565718399fSFrançois Tigeot group->num_connectors++] = connector->base.id; 9575718399fSFrançois Tigeot 9585718399fSFrançois Tigeot return 0; 9595718399fSFrançois Tigeot } 9605718399fSFrançois Tigeot 9615718399fSFrançois Tigeot /** 9625718399fSFrançois Tigeot * drm_mode_config_cleanup - free up DRM mode_config info 9635718399fSFrançois Tigeot * @dev: DRM device 9645718399fSFrançois Tigeot * 9655718399fSFrançois Tigeot * LOCKING: 9665718399fSFrançois Tigeot * Caller must hold mode config lock. 9675718399fSFrançois Tigeot * 9685718399fSFrançois Tigeot * Free up all the connectors and CRTCs associated with this DRM device, then 9695718399fSFrançois Tigeot * free up the framebuffers and associated buffer objects. 9705718399fSFrançois Tigeot * 9715718399fSFrançois Tigeot * FIXME: cleanup any dangling user buffer objects too 9725718399fSFrançois Tigeot */ 9735718399fSFrançois Tigeot void drm_mode_config_cleanup(struct drm_device *dev) 9745718399fSFrançois Tigeot { 9755718399fSFrançois Tigeot struct drm_connector *connector, *ot; 9765718399fSFrançois Tigeot struct drm_crtc *crtc, *ct; 9775718399fSFrançois Tigeot struct drm_encoder *encoder, *enct; 9785718399fSFrançois Tigeot struct drm_framebuffer *fb, *fbt; 9795718399fSFrançois Tigeot struct drm_property *property, *pt; 9805718399fSFrançois Tigeot struct drm_plane *plane, *plt; 9815718399fSFrançois Tigeot 9825718399fSFrançois Tigeot list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 9835718399fSFrançois Tigeot head) { 9845718399fSFrançois Tigeot encoder->funcs->destroy(encoder); 9855718399fSFrançois Tigeot } 9865718399fSFrançois Tigeot 9875718399fSFrançois Tigeot list_for_each_entry_safe(connector, ot, 9885718399fSFrançois Tigeot &dev->mode_config.connector_list, head) { 9895718399fSFrançois Tigeot connector->funcs->destroy(connector); 9905718399fSFrançois Tigeot } 9915718399fSFrançois Tigeot 9925718399fSFrançois Tigeot list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 9935718399fSFrançois Tigeot head) { 9945718399fSFrançois Tigeot drm_property_destroy(dev, property); 9955718399fSFrançois Tigeot } 9965718399fSFrançois Tigeot 9975718399fSFrançois Tigeot list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 9985718399fSFrançois Tigeot fb->funcs->destroy(fb); 9995718399fSFrançois Tigeot } 10005718399fSFrançois Tigeot 10015718399fSFrançois Tigeot list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 10025718399fSFrançois Tigeot crtc->funcs->destroy(crtc); 10035718399fSFrançois Tigeot } 10045718399fSFrançois Tigeot 10055718399fSFrançois Tigeot list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 10065718399fSFrançois Tigeot head) { 10075718399fSFrançois Tigeot plane->funcs->destroy(plane); 10085718399fSFrançois Tigeot } 1009aea8bdbdSFrançois Tigeot 1010aea8bdbdSFrançois Tigeot list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 1011aea8bdbdSFrançois Tigeot crtc->funcs->destroy(crtc); 1012aea8bdbdSFrançois Tigeot } 1013aea8bdbdSFrançois Tigeot 1014aea8bdbdSFrançois Tigeot idr_remove_all(&dev->mode_config.crtc_idr); 1015aea8bdbdSFrançois Tigeot idr_destroy(&dev->mode_config.crtc_idr); 10165718399fSFrançois Tigeot } 10175718399fSFrançois Tigeot 10185718399fSFrançois Tigeot /** 10195718399fSFrançois Tigeot * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 10205718399fSFrançois Tigeot * @out: drm_mode_modeinfo struct to return to the user 10215718399fSFrançois Tigeot * @in: drm_display_mode to use 10225718399fSFrançois Tigeot * 10235718399fSFrançois Tigeot * LOCKING: 10245718399fSFrançois Tigeot * None. 10255718399fSFrançois Tigeot * 10265718399fSFrançois Tigeot * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 10275718399fSFrançois Tigeot * the user. 10285718399fSFrançois Tigeot */ 10295718399fSFrançois Tigeot static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 10305718399fSFrançois Tigeot const struct drm_display_mode *in) 10315718399fSFrançois Tigeot { 10325718399fSFrançois Tigeot if (in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 10335718399fSFrançois Tigeot in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 10345718399fSFrançois Tigeot in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 10355718399fSFrançois Tigeot in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 10365718399fSFrançois Tigeot in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX) 10375718399fSFrançois Tigeot kprintf("timing values too large for mode info\n"); 10385718399fSFrançois Tigeot 10395718399fSFrançois Tigeot out->clock = in->clock; 10405718399fSFrançois Tigeot out->hdisplay = in->hdisplay; 10415718399fSFrançois Tigeot out->hsync_start = in->hsync_start; 10425718399fSFrançois Tigeot out->hsync_end = in->hsync_end; 10435718399fSFrançois Tigeot out->htotal = in->htotal; 10445718399fSFrançois Tigeot out->hskew = in->hskew; 10455718399fSFrançois Tigeot out->vdisplay = in->vdisplay; 10465718399fSFrançois Tigeot out->vsync_start = in->vsync_start; 10475718399fSFrançois Tigeot out->vsync_end = in->vsync_end; 10485718399fSFrançois Tigeot out->vtotal = in->vtotal; 10495718399fSFrançois Tigeot out->vscan = in->vscan; 10505718399fSFrançois Tigeot out->vrefresh = in->vrefresh; 10515718399fSFrançois Tigeot out->flags = in->flags; 10525718399fSFrançois Tigeot out->type = in->type; 10535718399fSFrançois Tigeot strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 10545718399fSFrançois Tigeot out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 10555718399fSFrançois Tigeot } 10565718399fSFrançois Tigeot 10575718399fSFrançois Tigeot /** 10585718399fSFrançois Tigeot * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode 10595718399fSFrançois Tigeot * @out: drm_display_mode to return to the user 10605718399fSFrançois Tigeot * @in: drm_mode_modeinfo to use 10615718399fSFrançois Tigeot * 10625718399fSFrançois Tigeot * LOCKING: 10635718399fSFrançois Tigeot * None. 10645718399fSFrançois Tigeot * 10655718399fSFrançois Tigeot * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 10665718399fSFrançois Tigeot * the caller. 10675718399fSFrançois Tigeot * 10685718399fSFrançois Tigeot * RETURNS: 10695718399fSFrançois Tigeot * Zero on success, errno on failure. 10705718399fSFrançois Tigeot */ 10715718399fSFrançois Tigeot static int drm_crtc_convert_umode(struct drm_display_mode *out, 10725718399fSFrançois Tigeot const struct drm_mode_modeinfo *in) 10735718399fSFrançois Tigeot { 10745718399fSFrançois Tigeot if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 10755718399fSFrançois Tigeot return ERANGE; 10765718399fSFrançois Tigeot 10775718399fSFrançois Tigeot out->clock = in->clock; 10785718399fSFrançois Tigeot out->hdisplay = in->hdisplay; 10795718399fSFrançois Tigeot out->hsync_start = in->hsync_start; 10805718399fSFrançois Tigeot out->hsync_end = in->hsync_end; 10815718399fSFrançois Tigeot out->htotal = in->htotal; 10825718399fSFrançois Tigeot out->hskew = in->hskew; 10835718399fSFrançois Tigeot out->vdisplay = in->vdisplay; 10845718399fSFrançois Tigeot out->vsync_start = in->vsync_start; 10855718399fSFrançois Tigeot out->vsync_end = in->vsync_end; 10865718399fSFrançois Tigeot out->vtotal = in->vtotal; 10875718399fSFrançois Tigeot out->vscan = in->vscan; 10885718399fSFrançois Tigeot out->vrefresh = in->vrefresh; 10895718399fSFrançois Tigeot out->flags = in->flags; 10905718399fSFrançois Tigeot out->type = in->type; 10915718399fSFrançois Tigeot strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 10925718399fSFrançois Tigeot out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 10935718399fSFrançois Tigeot 10945718399fSFrançois Tigeot return 0; 10955718399fSFrançois Tigeot } 10965718399fSFrançois Tigeot 10975718399fSFrançois Tigeot /** 10985718399fSFrançois Tigeot * drm_mode_getresources - get graphics configuration 10995718399fSFrançois Tigeot * @inode: inode from the ioctl 11005718399fSFrançois Tigeot * @filp: file * from the ioctl 11015718399fSFrançois Tigeot * @cmd: cmd from ioctl 11025718399fSFrançois Tigeot * @arg: arg from ioctl 11035718399fSFrançois Tigeot * 11045718399fSFrançois Tigeot * LOCKING: 11055718399fSFrançois Tigeot * Takes mode config lock. 11065718399fSFrançois Tigeot * 11075718399fSFrançois Tigeot * Construct a set of configuration description structures and return 11085718399fSFrançois Tigeot * them to the user, including CRTC, connector and framebuffer configuration. 11095718399fSFrançois Tigeot * 11105718399fSFrançois Tigeot * Called by the user via ioctl. 11115718399fSFrançois Tigeot * 11125718399fSFrançois Tigeot * RETURNS: 11135718399fSFrançois Tigeot * Zero on success, errno on failure. 11145718399fSFrançois Tigeot */ 11155718399fSFrançois Tigeot int drm_mode_getresources(struct drm_device *dev, void *data, 11165718399fSFrançois Tigeot struct drm_file *file_priv) 11175718399fSFrançois Tigeot { 11185718399fSFrançois Tigeot struct drm_mode_card_res *card_res = data; 11195718399fSFrançois Tigeot struct list_head *lh; 11205718399fSFrançois Tigeot struct drm_framebuffer *fb; 11215718399fSFrançois Tigeot struct drm_connector *connector; 11225718399fSFrançois Tigeot struct drm_crtc *crtc; 11235718399fSFrançois Tigeot struct drm_encoder *encoder; 11245718399fSFrançois Tigeot int ret = 0; 11255718399fSFrançois Tigeot int connector_count = 0; 11265718399fSFrançois Tigeot int crtc_count = 0; 11275718399fSFrançois Tigeot int fb_count = 0; 11285718399fSFrançois Tigeot int encoder_count = 0; 11295718399fSFrançois Tigeot int copied = 0, i; 11305718399fSFrançois Tigeot uint32_t __user *fb_id; 11315718399fSFrançois Tigeot uint32_t __user *crtc_id; 11325718399fSFrançois Tigeot uint32_t __user *connector_id; 11335718399fSFrançois Tigeot uint32_t __user *encoder_id; 11345718399fSFrançois Tigeot struct drm_mode_group *mode_group; 11355718399fSFrançois Tigeot 11365718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 11375718399fSFrançois Tigeot return (EINVAL); 11385718399fSFrançois Tigeot 11395718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 11405718399fSFrançois Tigeot 11415718399fSFrançois Tigeot /* 11425718399fSFrançois Tigeot * For the non-control nodes we need to limit the list of resources 11435718399fSFrançois Tigeot * by IDs in the group list for this node 11445718399fSFrançois Tigeot */ 11455718399fSFrançois Tigeot list_for_each(lh, &file_priv->fbs) 11465718399fSFrançois Tigeot fb_count++; 11475718399fSFrançois Tigeot 11485718399fSFrançois Tigeot #if 1 11495718399fSFrançois Tigeot mode_group = NULL; /* XXXKIB */ 11505718399fSFrançois Tigeot if (1 || file_priv->master) { 11515718399fSFrançois Tigeot #else 11525718399fSFrançois Tigeot mode_group = &file_priv->masterp->minor->mode_group; 11535718399fSFrançois Tigeot if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 11545718399fSFrançois Tigeot #endif 11555718399fSFrançois Tigeot 11565718399fSFrançois Tigeot list_for_each(lh, &dev->mode_config.crtc_list) 11575718399fSFrançois Tigeot crtc_count++; 11585718399fSFrançois Tigeot 11595718399fSFrançois Tigeot list_for_each(lh, &dev->mode_config.connector_list) 11605718399fSFrançois Tigeot connector_count++; 11615718399fSFrançois Tigeot 11625718399fSFrançois Tigeot list_for_each(lh, &dev->mode_config.encoder_list) 11635718399fSFrançois Tigeot encoder_count++; 11645718399fSFrançois Tigeot } else { 11655718399fSFrançois Tigeot 11665718399fSFrançois Tigeot crtc_count = mode_group->num_crtcs; 11675718399fSFrançois Tigeot connector_count = mode_group->num_connectors; 11685718399fSFrançois Tigeot encoder_count = mode_group->num_encoders; 11695718399fSFrançois Tigeot } 11705718399fSFrançois Tigeot 11715718399fSFrançois Tigeot card_res->max_height = dev->mode_config.max_height; 11725718399fSFrançois Tigeot card_res->min_height = dev->mode_config.min_height; 11735718399fSFrançois Tigeot card_res->max_width = dev->mode_config.max_width; 11745718399fSFrançois Tigeot card_res->min_width = dev->mode_config.min_width; 11755718399fSFrançois Tigeot 11765718399fSFrançois Tigeot /* handle this in 4 parts */ 11775718399fSFrançois Tigeot /* FBs */ 11785718399fSFrançois Tigeot if (card_res->count_fbs >= fb_count) { 11795718399fSFrançois Tigeot copied = 0; 11805718399fSFrançois Tigeot fb_id = (uint32_t *)(uintptr_t)card_res->fb_id_ptr; 11815718399fSFrançois Tigeot list_for_each_entry(fb, &file_priv->fbs, filp_head) { 11825718399fSFrançois Tigeot if (copyout(&fb->base.id, fb_id + copied, 11835718399fSFrançois Tigeot sizeof(uint32_t))) { 11845718399fSFrançois Tigeot ret = EFAULT; 11855718399fSFrançois Tigeot goto out; 11865718399fSFrançois Tigeot } 11875718399fSFrançois Tigeot copied++; 11885718399fSFrançois Tigeot } 11895718399fSFrançois Tigeot } 11905718399fSFrançois Tigeot card_res->count_fbs = fb_count; 11915718399fSFrançois Tigeot 11925718399fSFrançois Tigeot /* CRTCs */ 11935718399fSFrançois Tigeot if (card_res->count_crtcs >= crtc_count) { 11945718399fSFrançois Tigeot copied = 0; 11955718399fSFrançois Tigeot crtc_id = (uint32_t *)(uintptr_t)card_res->crtc_id_ptr; 11965718399fSFrançois Tigeot #if 1 11975718399fSFrançois Tigeot if (1 || file_priv->master) { 11985718399fSFrançois Tigeot #else 11995718399fSFrançois Tigeot if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 12005718399fSFrançois Tigeot #endif 12015718399fSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, 12025718399fSFrançois Tigeot head) { 12035718399fSFrançois Tigeot DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 12045718399fSFrançois Tigeot if (copyout(&crtc->base.id, crtc_id + 12055718399fSFrançois Tigeot copied, sizeof(uint32_t))) { 12065718399fSFrançois Tigeot ret = EFAULT; 12075718399fSFrançois Tigeot goto out; 12085718399fSFrançois Tigeot } 12095718399fSFrançois Tigeot copied++; 12105718399fSFrançois Tigeot } 12115718399fSFrançois Tigeot } else { 12125718399fSFrançois Tigeot for (i = 0; i < mode_group->num_crtcs; i++) { 12135718399fSFrançois Tigeot if (copyout(&mode_group->id_list[i], 12145718399fSFrançois Tigeot crtc_id + copied, sizeof(uint32_t))) { 12155718399fSFrançois Tigeot ret = EFAULT; 12165718399fSFrançois Tigeot goto out; 12175718399fSFrançois Tigeot } 12185718399fSFrançois Tigeot copied++; 12195718399fSFrançois Tigeot } 12205718399fSFrançois Tigeot } 12215718399fSFrançois Tigeot } 12225718399fSFrançois Tigeot card_res->count_crtcs = crtc_count; 12235718399fSFrançois Tigeot 12245718399fSFrançois Tigeot /* Encoders */ 12255718399fSFrançois Tigeot if (card_res->count_encoders >= encoder_count) { 12265718399fSFrançois Tigeot copied = 0; 12275718399fSFrançois Tigeot encoder_id = (uint32_t *)(uintptr_t)card_res->encoder_id_ptr; 12285718399fSFrançois Tigeot #if 1 12295718399fSFrançois Tigeot if (file_priv->master) { 12305718399fSFrançois Tigeot #else 12315718399fSFrançois Tigeot if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 12325718399fSFrançois Tigeot #endif 12335718399fSFrançois Tigeot list_for_each_entry(encoder, 12345718399fSFrançois Tigeot &dev->mode_config.encoder_list, 12355718399fSFrançois Tigeot head) { 12365718399fSFrançois Tigeot DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 12375718399fSFrançois Tigeot drm_get_encoder_name(encoder)); 12385718399fSFrançois Tigeot if (copyout(&encoder->base.id, encoder_id + 12395718399fSFrançois Tigeot copied, sizeof(uint32_t))) { 12405718399fSFrançois Tigeot ret = EFAULT; 12415718399fSFrançois Tigeot goto out; 12425718399fSFrançois Tigeot } 12435718399fSFrançois Tigeot copied++; 12445718399fSFrançois Tigeot } 12455718399fSFrançois Tigeot } else { 12465718399fSFrançois Tigeot for (i = mode_group->num_crtcs; 12475718399fSFrançois Tigeot i < mode_group->num_crtcs + mode_group->num_encoders; 12485718399fSFrançois Tigeot i++) { 12495718399fSFrançois Tigeot if (copyout(&mode_group->id_list[i], 12505718399fSFrançois Tigeot encoder_id + copied, sizeof(uint32_t))) { 12515718399fSFrançois Tigeot ret = EFAULT; 12525718399fSFrançois Tigeot goto out; 12535718399fSFrançois Tigeot } 12545718399fSFrançois Tigeot copied++; 12555718399fSFrançois Tigeot } 12565718399fSFrançois Tigeot 12575718399fSFrançois Tigeot } 12585718399fSFrançois Tigeot } 12595718399fSFrançois Tigeot card_res->count_encoders = encoder_count; 12605718399fSFrançois Tigeot 12615718399fSFrançois Tigeot /* Connectors */ 12625718399fSFrançois Tigeot if (card_res->count_connectors >= connector_count) { 12635718399fSFrançois Tigeot copied = 0; 12645718399fSFrançois Tigeot connector_id = (uint32_t *)(uintptr_t)card_res->connector_id_ptr; 12655718399fSFrançois Tigeot #if 1 12665718399fSFrançois Tigeot if (file_priv->master) { 12675718399fSFrançois Tigeot #else 12685718399fSFrançois Tigeot if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 12695718399fSFrançois Tigeot #endif 12705718399fSFrançois Tigeot list_for_each_entry(connector, 12715718399fSFrançois Tigeot &dev->mode_config.connector_list, 12725718399fSFrançois Tigeot head) { 12735718399fSFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 12745718399fSFrançois Tigeot connector->base.id, 12755718399fSFrançois Tigeot drm_get_connector_name(connector)); 12765718399fSFrançois Tigeot if (copyout(&connector->base.id, 12775718399fSFrançois Tigeot connector_id + copied, sizeof(uint32_t))) { 12785718399fSFrançois Tigeot ret = EFAULT; 12795718399fSFrançois Tigeot goto out; 12805718399fSFrançois Tigeot } 12815718399fSFrançois Tigeot copied++; 12825718399fSFrançois Tigeot } 12835718399fSFrançois Tigeot } else { 12845718399fSFrançois Tigeot int start = mode_group->num_crtcs + 12855718399fSFrançois Tigeot mode_group->num_encoders; 12865718399fSFrançois Tigeot for (i = start; i < start + mode_group->num_connectors; i++) { 12875718399fSFrançois Tigeot if (copyout(&mode_group->id_list[i], 12885718399fSFrançois Tigeot connector_id + copied, sizeof(uint32_t))) { 12895718399fSFrançois Tigeot ret = EFAULT; 12905718399fSFrançois Tigeot goto out; 12915718399fSFrançois Tigeot } 12925718399fSFrançois Tigeot copied++; 12935718399fSFrançois Tigeot } 12945718399fSFrançois Tigeot } 12955718399fSFrançois Tigeot } 12965718399fSFrançois Tigeot card_res->count_connectors = connector_count; 12975718399fSFrançois Tigeot 12985718399fSFrançois Tigeot DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 12995718399fSFrançois Tigeot card_res->count_connectors, card_res->count_encoders); 13005718399fSFrançois Tigeot 13015718399fSFrançois Tigeot out: 13025718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 13035718399fSFrançois Tigeot return ret; 13045718399fSFrançois Tigeot } 13055718399fSFrançois Tigeot 13065718399fSFrançois Tigeot /** 13075718399fSFrançois Tigeot * drm_mode_getcrtc - get CRTC configuration 13085718399fSFrançois Tigeot * @inode: inode from the ioctl 13095718399fSFrançois Tigeot * @filp: file * from the ioctl 13105718399fSFrançois Tigeot * @cmd: cmd from ioctl 13115718399fSFrançois Tigeot * @arg: arg from ioctl 13125718399fSFrançois Tigeot * 13135718399fSFrançois Tigeot * LOCKING: 13145718399fSFrançois Tigeot * Takes mode config lock. 13155718399fSFrançois Tigeot * 13165718399fSFrançois Tigeot * Construct a CRTC configuration structure to return to the user. 13175718399fSFrançois Tigeot * 13185718399fSFrançois Tigeot * Called by the user via ioctl. 13195718399fSFrançois Tigeot * 13205718399fSFrançois Tigeot * RETURNS: 13215718399fSFrançois Tigeot * Zero on success, errno on failure. 13225718399fSFrançois Tigeot */ 13235718399fSFrançois Tigeot int drm_mode_getcrtc(struct drm_device *dev, 13245718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 13255718399fSFrançois Tigeot { 13265718399fSFrançois Tigeot struct drm_mode_crtc *crtc_resp = data; 13275718399fSFrançois Tigeot struct drm_crtc *crtc; 13285718399fSFrançois Tigeot struct drm_mode_object *obj; 13295718399fSFrançois Tigeot int ret = 0; 13305718399fSFrançois Tigeot 13315718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 13325718399fSFrançois Tigeot return (EINVAL); 13335718399fSFrançois Tigeot 13345718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 13355718399fSFrançois Tigeot 13365718399fSFrançois Tigeot obj = drm_mode_object_find(dev, crtc_resp->crtc_id, 13375718399fSFrançois Tigeot DRM_MODE_OBJECT_CRTC); 13385718399fSFrançois Tigeot if (!obj) { 13395718399fSFrançois Tigeot ret = (EINVAL); 13405718399fSFrançois Tigeot goto out; 13415718399fSFrançois Tigeot } 13425718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 13435718399fSFrançois Tigeot 13445718399fSFrançois Tigeot crtc_resp->x = crtc->x; 13455718399fSFrançois Tigeot crtc_resp->y = crtc->y; 13465718399fSFrançois Tigeot crtc_resp->gamma_size = crtc->gamma_size; 13475718399fSFrançois Tigeot if (crtc->fb) 13485718399fSFrançois Tigeot crtc_resp->fb_id = crtc->fb->base.id; 13495718399fSFrançois Tigeot else 13505718399fSFrançois Tigeot crtc_resp->fb_id = 0; 13515718399fSFrançois Tigeot 13525718399fSFrançois Tigeot if (crtc->enabled) { 13535718399fSFrançois Tigeot 13545718399fSFrançois Tigeot drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 13555718399fSFrançois Tigeot crtc_resp->mode_valid = 1; 13565718399fSFrançois Tigeot 13575718399fSFrançois Tigeot } else { 13585718399fSFrançois Tigeot crtc_resp->mode_valid = 0; 13595718399fSFrançois Tigeot } 13605718399fSFrançois Tigeot 13615718399fSFrançois Tigeot out: 13625718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 13635718399fSFrançois Tigeot return ret; 13645718399fSFrançois Tigeot } 13655718399fSFrançois Tigeot 13665718399fSFrançois Tigeot /** 13675718399fSFrançois Tigeot * drm_mode_getconnector - get connector configuration 13685718399fSFrançois Tigeot * @inode: inode from the ioctl 13695718399fSFrançois Tigeot * @filp: file * from the ioctl 13705718399fSFrançois Tigeot * @cmd: cmd from ioctl 13715718399fSFrançois Tigeot * @arg: arg from ioctl 13725718399fSFrançois Tigeot * 13735718399fSFrançois Tigeot * LOCKING: 13745718399fSFrançois Tigeot * Takes mode config lock. 13755718399fSFrançois Tigeot * 13765718399fSFrançois Tigeot * Construct a connector configuration structure to return to the user. 13775718399fSFrançois Tigeot * 13785718399fSFrançois Tigeot * Called by the user via ioctl. 13795718399fSFrançois Tigeot * 13805718399fSFrançois Tigeot * RETURNS: 13815718399fSFrançois Tigeot * Zero on success, errno on failure. 13825718399fSFrançois Tigeot */ 13835718399fSFrançois Tigeot int drm_mode_getconnector(struct drm_device *dev, void *data, 13845718399fSFrançois Tigeot struct drm_file *file_priv) 13855718399fSFrançois Tigeot { 13865718399fSFrançois Tigeot struct drm_mode_get_connector *out_resp = data; 13875718399fSFrançois Tigeot struct drm_mode_object *obj; 13885718399fSFrançois Tigeot struct drm_connector *connector; 13895718399fSFrançois Tigeot struct drm_display_mode *mode; 13905718399fSFrançois Tigeot int mode_count = 0; 13915718399fSFrançois Tigeot int props_count = 0; 13925718399fSFrançois Tigeot int encoders_count = 0; 13935718399fSFrançois Tigeot int ret = 0; 13945718399fSFrançois Tigeot int copied = 0; 13955718399fSFrançois Tigeot int i; 13965718399fSFrançois Tigeot struct drm_mode_modeinfo u_mode; 13975718399fSFrançois Tigeot struct drm_mode_modeinfo __user *mode_ptr; 13985718399fSFrançois Tigeot uint32_t *prop_ptr; 13995718399fSFrançois Tigeot uint64_t *prop_values; 14005718399fSFrançois Tigeot uint32_t *encoder_ptr; 14015718399fSFrançois Tigeot 14025718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 14035718399fSFrançois Tigeot return (EINVAL); 14045718399fSFrançois Tigeot 14055718399fSFrançois Tigeot memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 14065718399fSFrançois Tigeot 14075718399fSFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 14085718399fSFrançois Tigeot 14095718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 14105718399fSFrançois Tigeot 14115718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_resp->connector_id, 14125718399fSFrançois Tigeot DRM_MODE_OBJECT_CONNECTOR); 14135718399fSFrançois Tigeot if (!obj) { 14145718399fSFrançois Tigeot ret = EINVAL; 14155718399fSFrançois Tigeot goto out; 14165718399fSFrançois Tigeot } 14175718399fSFrançois Tigeot connector = obj_to_connector(obj); 14185718399fSFrançois Tigeot 14195718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 14205718399fSFrançois Tigeot if (connector->property_ids[i] != 0) { 14215718399fSFrançois Tigeot props_count++; 14225718399fSFrançois Tigeot } 14235718399fSFrançois Tigeot } 14245718399fSFrançois Tigeot 14255718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 14265718399fSFrançois Tigeot if (connector->encoder_ids[i] != 0) { 14275718399fSFrançois Tigeot encoders_count++; 14285718399fSFrançois Tigeot } 14295718399fSFrançois Tigeot } 14305718399fSFrançois Tigeot 14315718399fSFrançois Tigeot if (out_resp->count_modes == 0) { 14325718399fSFrançois Tigeot connector->funcs->fill_modes(connector, 14335718399fSFrançois Tigeot dev->mode_config.max_width, 14345718399fSFrançois Tigeot dev->mode_config.max_height); 14355718399fSFrançois Tigeot } 14365718399fSFrançois Tigeot 14375718399fSFrançois Tigeot /* delayed so we get modes regardless of pre-fill_modes state */ 14385718399fSFrançois Tigeot list_for_each_entry(mode, &connector->modes, head) 14395718399fSFrançois Tigeot mode_count++; 14405718399fSFrançois Tigeot 14415718399fSFrançois Tigeot out_resp->connector_id = connector->base.id; 14425718399fSFrançois Tigeot out_resp->connector_type = connector->connector_type; 14435718399fSFrançois Tigeot out_resp->connector_type_id = connector->connector_type_id; 14445718399fSFrançois Tigeot out_resp->mm_width = connector->display_info.width_mm; 14455718399fSFrançois Tigeot out_resp->mm_height = connector->display_info.height_mm; 14465718399fSFrançois Tigeot out_resp->subpixel = connector->display_info.subpixel_order; 14475718399fSFrançois Tigeot out_resp->connection = connector->status; 14485718399fSFrançois Tigeot if (connector->encoder) 14495718399fSFrançois Tigeot out_resp->encoder_id = connector->encoder->base.id; 14505718399fSFrançois Tigeot else 14515718399fSFrançois Tigeot out_resp->encoder_id = 0; 14525718399fSFrançois Tigeot 14535718399fSFrançois Tigeot /* 14545718399fSFrançois Tigeot * This ioctl is called twice, once to determine how much space is 14555718399fSFrançois Tigeot * needed, and the 2nd time to fill it. 14565718399fSFrançois Tigeot */ 14575718399fSFrançois Tigeot if ((out_resp->count_modes >= mode_count) && mode_count) { 14585718399fSFrançois Tigeot copied = 0; 14595718399fSFrançois Tigeot mode_ptr = (struct drm_mode_modeinfo *)(uintptr_t)out_resp->modes_ptr; 14605718399fSFrançois Tigeot list_for_each_entry(mode, &connector->modes, head) { 14615718399fSFrançois Tigeot drm_crtc_convert_to_umode(&u_mode, mode); 14625718399fSFrançois Tigeot if (copyout(&u_mode, mode_ptr + copied, 14635718399fSFrançois Tigeot sizeof(u_mode))) { 14645718399fSFrançois Tigeot ret = EFAULT; 14655718399fSFrançois Tigeot goto out; 14665718399fSFrançois Tigeot } 14675718399fSFrançois Tigeot copied++; 14685718399fSFrançois Tigeot } 14695718399fSFrançois Tigeot } 14705718399fSFrançois Tigeot out_resp->count_modes = mode_count; 14715718399fSFrançois Tigeot 14725718399fSFrançois Tigeot if ((out_resp->count_props >= props_count) && props_count) { 14735718399fSFrançois Tigeot copied = 0; 14745718399fSFrançois Tigeot prop_ptr = (uint32_t *)(uintptr_t)(out_resp->props_ptr); 14755718399fSFrançois Tigeot prop_values = (uint64_t *)(uintptr_t)(out_resp->prop_values_ptr); 14765718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 14775718399fSFrançois Tigeot if (connector->property_ids[i] != 0) { 14785718399fSFrançois Tigeot if (copyout(&connector->property_ids[i], 14795718399fSFrançois Tigeot prop_ptr + copied, sizeof(uint32_t))) { 14805718399fSFrançois Tigeot ret = EFAULT; 14815718399fSFrançois Tigeot goto out; 14825718399fSFrançois Tigeot } 14835718399fSFrançois Tigeot 14845718399fSFrançois Tigeot if (copyout(&connector->property_values[i], 14855718399fSFrançois Tigeot prop_values + copied, sizeof(uint64_t))) { 14865718399fSFrançois Tigeot ret = EFAULT; 14875718399fSFrançois Tigeot goto out; 14885718399fSFrançois Tigeot } 14895718399fSFrançois Tigeot copied++; 14905718399fSFrançois Tigeot } 14915718399fSFrançois Tigeot } 14925718399fSFrançois Tigeot } 14935718399fSFrançois Tigeot out_resp->count_props = props_count; 14945718399fSFrançois Tigeot 14955718399fSFrançois Tigeot if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 14965718399fSFrançois Tigeot copied = 0; 14975718399fSFrançois Tigeot encoder_ptr = (uint32_t *)(uintptr_t)(out_resp->encoders_ptr); 14985718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 14995718399fSFrançois Tigeot if (connector->encoder_ids[i] != 0) { 15005718399fSFrançois Tigeot if (copyout(&connector->encoder_ids[i], 15015718399fSFrançois Tigeot encoder_ptr + copied, sizeof(uint32_t))) { 15025718399fSFrançois Tigeot ret = EFAULT; 15035718399fSFrançois Tigeot goto out; 15045718399fSFrançois Tigeot } 15055718399fSFrançois Tigeot copied++; 15065718399fSFrançois Tigeot } 15075718399fSFrançois Tigeot } 15085718399fSFrançois Tigeot } 15095718399fSFrançois Tigeot out_resp->count_encoders = encoders_count; 15105718399fSFrançois Tigeot 15115718399fSFrançois Tigeot out: 15125718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 15135718399fSFrançois Tigeot return ret; 15145718399fSFrançois Tigeot } 15155718399fSFrançois Tigeot 15165718399fSFrançois Tigeot int drm_mode_getencoder(struct drm_device *dev, void *data, 15175718399fSFrançois Tigeot struct drm_file *file_priv) 15185718399fSFrançois Tigeot { 15195718399fSFrançois Tigeot struct drm_mode_get_encoder *enc_resp = data; 15205718399fSFrançois Tigeot struct drm_mode_object *obj; 15215718399fSFrançois Tigeot struct drm_encoder *encoder; 15225718399fSFrançois Tigeot int ret = 0; 15235718399fSFrançois Tigeot 15245718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 15255718399fSFrançois Tigeot return (EINVAL); 15265718399fSFrançois Tigeot 15275718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 15285718399fSFrançois Tigeot obj = drm_mode_object_find(dev, enc_resp->encoder_id, 15295718399fSFrançois Tigeot DRM_MODE_OBJECT_ENCODER); 15305718399fSFrançois Tigeot if (!obj) { 15315718399fSFrançois Tigeot ret = EINVAL; 15325718399fSFrançois Tigeot goto out; 15335718399fSFrançois Tigeot } 15345718399fSFrançois Tigeot encoder = obj_to_encoder(obj); 15355718399fSFrançois Tigeot 15365718399fSFrançois Tigeot if (encoder->crtc) 15375718399fSFrançois Tigeot enc_resp->crtc_id = encoder->crtc->base.id; 15385718399fSFrançois Tigeot else 15395718399fSFrançois Tigeot enc_resp->crtc_id = 0; 15405718399fSFrançois Tigeot enc_resp->encoder_type = encoder->encoder_type; 15415718399fSFrançois Tigeot enc_resp->encoder_id = encoder->base.id; 15425718399fSFrançois Tigeot enc_resp->possible_crtcs = encoder->possible_crtcs; 15435718399fSFrançois Tigeot enc_resp->possible_clones = encoder->possible_clones; 15445718399fSFrançois Tigeot 15455718399fSFrançois Tigeot out: 15465718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 15475718399fSFrançois Tigeot return ret; 15485718399fSFrançois Tigeot } 15495718399fSFrançois Tigeot 15505718399fSFrançois Tigeot /** 15515718399fSFrançois Tigeot * drm_mode_getplane_res - get plane info 15525718399fSFrançois Tigeot * @dev: DRM device 15535718399fSFrançois Tigeot * @data: ioctl data 15545718399fSFrançois Tigeot * @file_priv: DRM file info 15555718399fSFrançois Tigeot * 15565718399fSFrançois Tigeot * LOCKING: 15575718399fSFrançois Tigeot * Takes mode config lock. 15585718399fSFrançois Tigeot * 15595718399fSFrançois Tigeot * Return an plane count and set of IDs. 15605718399fSFrançois Tigeot */ 15615718399fSFrançois Tigeot int drm_mode_getplane_res(struct drm_device *dev, void *data, 15625718399fSFrançois Tigeot struct drm_file *file_priv) 15635718399fSFrançois Tigeot { 15645718399fSFrançois Tigeot struct drm_mode_get_plane_res *plane_resp = data; 15655718399fSFrançois Tigeot struct drm_mode_config *config; 15665718399fSFrançois Tigeot struct drm_plane *plane; 15675718399fSFrançois Tigeot uint32_t *plane_ptr; 15685718399fSFrançois Tigeot int copied = 0, ret = 0; 15695718399fSFrançois Tigeot 15705718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 15715718399fSFrançois Tigeot return (EINVAL); 15725718399fSFrançois Tigeot 15735718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 15745718399fSFrançois Tigeot config = &dev->mode_config; 15755718399fSFrançois Tigeot 15765718399fSFrançois Tigeot /* 15775718399fSFrançois Tigeot * This ioctl is called twice, once to determine how much space is 15785718399fSFrançois Tigeot * needed, and the 2nd time to fill it. 15795718399fSFrançois Tigeot */ 15805718399fSFrançois Tigeot if (config->num_plane && 15815718399fSFrançois Tigeot (plane_resp->count_planes >= config->num_plane)) { 15825718399fSFrançois Tigeot plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; 15835718399fSFrançois Tigeot 15845718399fSFrançois Tigeot list_for_each_entry(plane, &config->plane_list, head) { 15855718399fSFrançois Tigeot if (copyout(&plane->base.id, plane_ptr + copied, 15865718399fSFrançois Tigeot sizeof(uint32_t))) { 15875718399fSFrançois Tigeot ret = EFAULT; 15885718399fSFrançois Tigeot goto out; 15895718399fSFrançois Tigeot } 15905718399fSFrançois Tigeot copied++; 15915718399fSFrançois Tigeot } 15925718399fSFrançois Tigeot } 15935718399fSFrançois Tigeot plane_resp->count_planes = config->num_plane; 15945718399fSFrançois Tigeot 15955718399fSFrançois Tigeot out: 15965718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 15975718399fSFrançois Tigeot return ret; 15985718399fSFrançois Tigeot } 15995718399fSFrançois Tigeot 16005718399fSFrançois Tigeot /** 16015718399fSFrançois Tigeot * drm_mode_getplane - get plane info 16025718399fSFrançois Tigeot * @dev: DRM device 16035718399fSFrançois Tigeot * @data: ioctl data 16045718399fSFrançois Tigeot * @file_priv: DRM file info 16055718399fSFrançois Tigeot * 16065718399fSFrançois Tigeot * LOCKING: 16075718399fSFrançois Tigeot * Takes mode config lock. 16085718399fSFrançois Tigeot * 16095718399fSFrançois Tigeot * Return plane info, including formats supported, gamma size, any 16105718399fSFrançois Tigeot * current fb, etc. 16115718399fSFrançois Tigeot */ 16125718399fSFrançois Tigeot int drm_mode_getplane(struct drm_device *dev, void *data, 16135718399fSFrançois Tigeot struct drm_file *file_priv) 16145718399fSFrançois Tigeot { 16155718399fSFrançois Tigeot struct drm_mode_get_plane *plane_resp = data; 16165718399fSFrançois Tigeot struct drm_mode_object *obj; 16175718399fSFrançois Tigeot struct drm_plane *plane; 16185718399fSFrançois Tigeot uint32_t *format_ptr; 16195718399fSFrançois Tigeot int ret = 0; 16205718399fSFrançois Tigeot 16215718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 16225718399fSFrançois Tigeot return (EINVAL); 16235718399fSFrançois Tigeot 16245718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 16255718399fSFrançois Tigeot obj = drm_mode_object_find(dev, plane_resp->plane_id, 16265718399fSFrançois Tigeot DRM_MODE_OBJECT_PLANE); 16275718399fSFrançois Tigeot if (!obj) { 16285718399fSFrançois Tigeot ret = ENOENT; 16295718399fSFrançois Tigeot goto out; 16305718399fSFrançois Tigeot } 16315718399fSFrançois Tigeot plane = obj_to_plane(obj); 16325718399fSFrançois Tigeot 16335718399fSFrançois Tigeot if (plane->crtc) 16345718399fSFrançois Tigeot plane_resp->crtc_id = plane->crtc->base.id; 16355718399fSFrançois Tigeot else 16365718399fSFrançois Tigeot plane_resp->crtc_id = 0; 16375718399fSFrançois Tigeot 16385718399fSFrançois Tigeot if (plane->fb) 16395718399fSFrançois Tigeot plane_resp->fb_id = plane->fb->base.id; 16405718399fSFrançois Tigeot else 16415718399fSFrançois Tigeot plane_resp->fb_id = 0; 16425718399fSFrançois Tigeot 16435718399fSFrançois Tigeot plane_resp->plane_id = plane->base.id; 16445718399fSFrançois Tigeot plane_resp->possible_crtcs = plane->possible_crtcs; 16455718399fSFrançois Tigeot plane_resp->gamma_size = plane->gamma_size; 16465718399fSFrançois Tigeot 16475718399fSFrançois Tigeot /* 16485718399fSFrançois Tigeot * This ioctl is called twice, once to determine how much space is 16495718399fSFrançois Tigeot * needed, and the 2nd time to fill it. 16505718399fSFrançois Tigeot */ 16515718399fSFrançois Tigeot if (plane->format_count && 16525718399fSFrançois Tigeot (plane_resp->count_format_types >= plane->format_count)) { 16535718399fSFrançois Tigeot format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; 16545718399fSFrançois Tigeot if (copyout(format_ptr, 16555718399fSFrançois Tigeot plane->format_types, 16565718399fSFrançois Tigeot sizeof(uint32_t) * plane->format_count)) { 16575718399fSFrançois Tigeot ret = EFAULT; 16585718399fSFrançois Tigeot goto out; 16595718399fSFrançois Tigeot } 16605718399fSFrançois Tigeot } 16615718399fSFrançois Tigeot plane_resp->count_format_types = plane->format_count; 16625718399fSFrançois Tigeot 16635718399fSFrançois Tigeot out: 16645718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 16655718399fSFrançois Tigeot return ret; 16665718399fSFrançois Tigeot } 16675718399fSFrançois Tigeot 16685718399fSFrançois Tigeot /** 16695718399fSFrançois Tigeot * drm_mode_setplane - set up or tear down an plane 16705718399fSFrançois Tigeot * @dev: DRM device 16715718399fSFrançois Tigeot * @data: ioctl data* 16725718399fSFrançois Tigeot * @file_prive: DRM file info 16735718399fSFrançois Tigeot * 16745718399fSFrançois Tigeot * LOCKING: 16755718399fSFrançois Tigeot * Takes mode config lock. 16765718399fSFrançois Tigeot * 16775718399fSFrançois Tigeot * Set plane info, including placement, fb, scaling, and other factors. 16785718399fSFrançois Tigeot * Or pass a NULL fb to disable. 16795718399fSFrançois Tigeot */ 16805718399fSFrançois Tigeot int drm_mode_setplane(struct drm_device *dev, void *data, 16815718399fSFrançois Tigeot struct drm_file *file_priv) 16825718399fSFrançois Tigeot { 16835718399fSFrançois Tigeot struct drm_mode_set_plane *plane_req = data; 16845718399fSFrançois Tigeot struct drm_mode_object *obj; 16855718399fSFrançois Tigeot struct drm_plane *plane; 16865718399fSFrançois Tigeot struct drm_crtc *crtc; 16875718399fSFrançois Tigeot struct drm_framebuffer *fb; 16885718399fSFrançois Tigeot int ret = 0; 16895718399fSFrançois Tigeot unsigned int fb_width, fb_height; 16905718399fSFrançois Tigeot int i; 16915718399fSFrançois Tigeot 16925718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 16935718399fSFrançois Tigeot return (EINVAL); 16945718399fSFrançois Tigeot 16955718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 16965718399fSFrançois Tigeot 16975718399fSFrançois Tigeot /* 16985718399fSFrançois Tigeot * First, find the plane, crtc, and fb objects. If not available, 16995718399fSFrançois Tigeot * we don't bother to call the driver. 17005718399fSFrançois Tigeot */ 17015718399fSFrançois Tigeot obj = drm_mode_object_find(dev, plane_req->plane_id, 17025718399fSFrançois Tigeot DRM_MODE_OBJECT_PLANE); 17035718399fSFrançois Tigeot if (!obj) { 17045718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown plane ID %d\n", 17055718399fSFrançois Tigeot plane_req->plane_id); 17065718399fSFrançois Tigeot ret = ENOENT; 17075718399fSFrançois Tigeot goto out; 17085718399fSFrançois Tigeot } 17095718399fSFrançois Tigeot plane = obj_to_plane(obj); 17105718399fSFrançois Tigeot 17115718399fSFrançois Tigeot /* No fb means shut it down */ 17125718399fSFrançois Tigeot if (!plane_req->fb_id) { 17135718399fSFrançois Tigeot plane->funcs->disable_plane(plane); 17145718399fSFrançois Tigeot plane->crtc = NULL; 17155718399fSFrançois Tigeot plane->fb = NULL; 17165718399fSFrançois Tigeot goto out; 17175718399fSFrançois Tigeot } 17185718399fSFrançois Tigeot 17195718399fSFrançois Tigeot obj = drm_mode_object_find(dev, plane_req->crtc_id, 17205718399fSFrançois Tigeot DRM_MODE_OBJECT_CRTC); 17215718399fSFrançois Tigeot if (!obj) { 17225718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown crtc ID %d\n", 17235718399fSFrançois Tigeot plane_req->crtc_id); 17245718399fSFrançois Tigeot ret = ENOENT; 17255718399fSFrançois Tigeot goto out; 17265718399fSFrançois Tigeot } 17275718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 17285718399fSFrançois Tigeot 17295718399fSFrançois Tigeot obj = drm_mode_object_find(dev, plane_req->fb_id, 17305718399fSFrançois Tigeot DRM_MODE_OBJECT_FB); 17315718399fSFrançois Tigeot if (!obj) { 17325718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 17335718399fSFrançois Tigeot plane_req->fb_id); 17345718399fSFrançois Tigeot ret = ENOENT; 17355718399fSFrançois Tigeot goto out; 17365718399fSFrançois Tigeot } 17375718399fSFrançois Tigeot fb = obj_to_fb(obj); 17385718399fSFrançois Tigeot 17395718399fSFrançois Tigeot /* Check whether this plane supports the fb pixel format. */ 17405718399fSFrançois Tigeot for (i = 0; i < plane->format_count; i++) 17415718399fSFrançois Tigeot if (fb->pixel_format == plane->format_types[i]) 17425718399fSFrançois Tigeot break; 17435718399fSFrançois Tigeot if (i == plane->format_count) { 17445718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); 17455718399fSFrançois Tigeot ret = EINVAL; 17465718399fSFrançois Tigeot goto out; 17475718399fSFrançois Tigeot } 17485718399fSFrançois Tigeot 17495718399fSFrançois Tigeot fb_width = fb->width << 16; 17505718399fSFrançois Tigeot fb_height = fb->height << 16; 17515718399fSFrançois Tigeot 17525718399fSFrançois Tigeot /* Make sure source coordinates are inside the fb. */ 17535718399fSFrançois Tigeot if (plane_req->src_w > fb_width || 17545718399fSFrançois Tigeot plane_req->src_x > fb_width - plane_req->src_w || 17555718399fSFrançois Tigeot plane_req->src_h > fb_height || 17565718399fSFrançois Tigeot plane_req->src_y > fb_height - plane_req->src_h) { 17575718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid source coordinates " 17585718399fSFrançois Tigeot "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 17595718399fSFrançois Tigeot plane_req->src_w >> 16, 17605718399fSFrançois Tigeot ((plane_req->src_w & 0xffff) * 15625) >> 10, 17615718399fSFrançois Tigeot plane_req->src_h >> 16, 17625718399fSFrançois Tigeot ((plane_req->src_h & 0xffff) * 15625) >> 10, 17635718399fSFrançois Tigeot plane_req->src_x >> 16, 17645718399fSFrançois Tigeot ((plane_req->src_x & 0xffff) * 15625) >> 10, 17655718399fSFrançois Tigeot plane_req->src_y >> 16, 17665718399fSFrançois Tigeot ((plane_req->src_y & 0xffff) * 15625) >> 10); 17675718399fSFrançois Tigeot ret = ENOSPC; 17685718399fSFrançois Tigeot goto out; 17695718399fSFrançois Tigeot } 17705718399fSFrançois Tigeot 17715718399fSFrançois Tigeot /* Give drivers some help against integer overflows */ 17725718399fSFrançois Tigeot if (plane_req->crtc_w > INT_MAX || 17735718399fSFrançois Tigeot plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 17745718399fSFrançois Tigeot plane_req->crtc_h > INT_MAX || 17755718399fSFrançois Tigeot plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 17765718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 17775718399fSFrançois Tigeot plane_req->crtc_w, plane_req->crtc_h, 17785718399fSFrançois Tigeot plane_req->crtc_x, plane_req->crtc_y); 17795718399fSFrançois Tigeot ret = ERANGE; 17805718399fSFrançois Tigeot goto out; 17815718399fSFrançois Tigeot } 17825718399fSFrançois Tigeot 17835718399fSFrançois Tigeot ret = -plane->funcs->update_plane(plane, crtc, fb, 17845718399fSFrançois Tigeot plane_req->crtc_x, plane_req->crtc_y, 17855718399fSFrançois Tigeot plane_req->crtc_w, plane_req->crtc_h, 17865718399fSFrançois Tigeot plane_req->src_x, plane_req->src_y, 17875718399fSFrançois Tigeot plane_req->src_w, plane_req->src_h); 17885718399fSFrançois Tigeot if (!ret) { 17895718399fSFrançois Tigeot plane->crtc = crtc; 17905718399fSFrançois Tigeot plane->fb = fb; 17915718399fSFrançois Tigeot } 17925718399fSFrançois Tigeot 17935718399fSFrançois Tigeot out: 17945718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 17955718399fSFrançois Tigeot 17965718399fSFrançois Tigeot return ret; 17975718399fSFrançois Tigeot } 17985718399fSFrançois Tigeot 17995718399fSFrançois Tigeot /** 18005718399fSFrançois Tigeot * drm_mode_setcrtc - set CRTC configuration 18015718399fSFrançois Tigeot * @inode: inode from the ioctl 18025718399fSFrançois Tigeot * @filp: file * from the ioctl 18035718399fSFrançois Tigeot * @cmd: cmd from ioctl 18045718399fSFrançois Tigeot * @arg: arg from ioctl 18055718399fSFrançois Tigeot * 18065718399fSFrançois Tigeot * LOCKING: 18075718399fSFrançois Tigeot * Takes mode config lock. 18085718399fSFrançois Tigeot * 18095718399fSFrançois Tigeot * Build a new CRTC configuration based on user request. 18105718399fSFrançois Tigeot * 18115718399fSFrançois Tigeot * Called by the user via ioctl. 18125718399fSFrançois Tigeot * 18135718399fSFrançois Tigeot * RETURNS: 18145718399fSFrançois Tigeot * Zero on success, errno on failure. 18155718399fSFrançois Tigeot */ 18165718399fSFrançois Tigeot int drm_mode_setcrtc(struct drm_device *dev, void *data, 18175718399fSFrançois Tigeot struct drm_file *file_priv) 18185718399fSFrançois Tigeot { 18195718399fSFrançois Tigeot struct drm_mode_config *config = &dev->mode_config; 18205718399fSFrançois Tigeot struct drm_mode_crtc *crtc_req = data; 18215718399fSFrançois Tigeot struct drm_mode_object *obj; 18225718399fSFrançois Tigeot struct drm_crtc *crtc; 18235718399fSFrançois Tigeot struct drm_connector **connector_set = NULL, *connector; 18245718399fSFrançois Tigeot struct drm_framebuffer *fb = NULL; 18255718399fSFrançois Tigeot struct drm_display_mode *mode = NULL; 18265718399fSFrançois Tigeot struct drm_mode_set set; 18275718399fSFrançois Tigeot uint32_t *set_connectors_ptr; 18285718399fSFrançois Tigeot int ret = 0; 18295718399fSFrançois Tigeot int i; 18305718399fSFrançois Tigeot 18315718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 18325718399fSFrançois Tigeot return (EINVAL); 18335718399fSFrançois Tigeot 18345718399fSFrançois Tigeot /* For some reason crtc x/y offsets are signed internally. */ 18355718399fSFrançois Tigeot if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 18365718399fSFrançois Tigeot return (ERANGE); 18375718399fSFrançois Tigeot 18385718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 18395718399fSFrançois Tigeot obj = drm_mode_object_find(dev, crtc_req->crtc_id, 18405718399fSFrançois Tigeot DRM_MODE_OBJECT_CRTC); 18415718399fSFrançois Tigeot if (!obj) { 18425718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 18435718399fSFrançois Tigeot ret = EINVAL; 18445718399fSFrançois Tigeot goto out; 18455718399fSFrançois Tigeot } 18465718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 18475718399fSFrançois Tigeot DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 18485718399fSFrançois Tigeot 18495718399fSFrançois Tigeot if (crtc_req->mode_valid) { 18505718399fSFrançois Tigeot /* If we have a mode we need a framebuffer. */ 18515718399fSFrançois Tigeot /* If we pass -1, set the mode with the currently bound fb */ 18525718399fSFrançois Tigeot if (crtc_req->fb_id == -1) { 18535718399fSFrançois Tigeot if (!crtc->fb) { 18545718399fSFrançois Tigeot DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 18555718399fSFrançois Tigeot ret = -EINVAL; 18565718399fSFrançois Tigeot goto out; 18575718399fSFrançois Tigeot } 18585718399fSFrançois Tigeot fb = crtc->fb; 18595718399fSFrançois Tigeot } else { 18605718399fSFrançois Tigeot obj = drm_mode_object_find(dev, crtc_req->fb_id, 18615718399fSFrançois Tigeot DRM_MODE_OBJECT_FB); 18625718399fSFrançois Tigeot if (!obj) { 18635718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown FB ID%d\n", 18645718399fSFrançois Tigeot crtc_req->fb_id); 18655718399fSFrançois Tigeot ret = EINVAL; 18665718399fSFrançois Tigeot goto out; 18675718399fSFrançois Tigeot } 18685718399fSFrançois Tigeot fb = obj_to_fb(obj); 18695718399fSFrançois Tigeot } 18705718399fSFrançois Tigeot 18715718399fSFrançois Tigeot mode = drm_mode_create(dev); 18725718399fSFrançois Tigeot if (!mode) { 18735718399fSFrançois Tigeot ret = ENOMEM; 18745718399fSFrançois Tigeot goto out; 18755718399fSFrançois Tigeot } 18765718399fSFrançois Tigeot 18775718399fSFrançois Tigeot ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 18785718399fSFrançois Tigeot if (ret) { 18795718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid mode\n"); 18805718399fSFrançois Tigeot goto out; 18815718399fSFrançois Tigeot } 18825718399fSFrançois Tigeot 18835718399fSFrançois Tigeot drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 18845718399fSFrançois Tigeot 18855718399fSFrançois Tigeot if (mode->hdisplay > fb->width || 18865718399fSFrançois Tigeot mode->vdisplay > fb->height || 18875718399fSFrançois Tigeot crtc_req->x > fb->width - mode->hdisplay || 18885718399fSFrançois Tigeot crtc_req->y > fb->height - mode->vdisplay) { 18895718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n", 18905718399fSFrançois Tigeot mode->hdisplay, mode->vdisplay, 18915718399fSFrançois Tigeot crtc_req->x, crtc_req->y, 18925718399fSFrançois Tigeot fb->width, fb->height); 18935718399fSFrançois Tigeot ret = ENOSPC; 18945718399fSFrançois Tigeot goto out; 18955718399fSFrançois Tigeot } 18965718399fSFrançois Tigeot } 18975718399fSFrançois Tigeot 18985718399fSFrançois Tigeot if (crtc_req->count_connectors == 0 && mode) { 18995718399fSFrançois Tigeot DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 19005718399fSFrançois Tigeot ret = EINVAL; 19015718399fSFrançois Tigeot goto out; 19025718399fSFrançois Tigeot } 19035718399fSFrançois Tigeot 19045718399fSFrançois Tigeot if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 19055718399fSFrançois Tigeot DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 19065718399fSFrançois Tigeot crtc_req->count_connectors); 19075718399fSFrançois Tigeot ret = EINVAL; 19085718399fSFrançois Tigeot goto out; 19095718399fSFrançois Tigeot } 19105718399fSFrançois Tigeot 19115718399fSFrançois Tigeot if (crtc_req->count_connectors > 0) { 19125718399fSFrançois Tigeot u32 out_id; 19135718399fSFrançois Tigeot 19145718399fSFrançois Tigeot /* Avoid unbounded kernel memory allocation */ 19155718399fSFrançois Tigeot if (crtc_req->count_connectors > config->num_connector) { 19165718399fSFrançois Tigeot ret = EINVAL; 19175718399fSFrançois Tigeot goto out; 19185718399fSFrançois Tigeot } 19195718399fSFrançois Tigeot 19205718399fSFrançois Tigeot connector_set = kmalloc(crtc_req->count_connectors * 19215718399fSFrançois Tigeot sizeof(struct drm_connector *), DRM_MEM_KMS, M_WAITOK); 19225718399fSFrançois Tigeot 19235718399fSFrançois Tigeot for (i = 0; i < crtc_req->count_connectors; i++) { 19245718399fSFrançois Tigeot set_connectors_ptr = (uint32_t *)(uintptr_t)crtc_req->set_connectors_ptr; 19255718399fSFrançois Tigeot if (copyin(&set_connectors_ptr[i], &out_id, sizeof(uint32_t))) { 19265718399fSFrançois Tigeot ret = EFAULT; 19275718399fSFrançois Tigeot goto out; 19285718399fSFrançois Tigeot } 19295718399fSFrançois Tigeot 19305718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_id, 19315718399fSFrançois Tigeot DRM_MODE_OBJECT_CONNECTOR); 19325718399fSFrançois Tigeot if (!obj) { 19335718399fSFrançois Tigeot DRM_DEBUG_KMS("Connector id %d unknown\n", 19345718399fSFrançois Tigeot out_id); 19355718399fSFrançois Tigeot ret = EINVAL; 19365718399fSFrançois Tigeot goto out; 19375718399fSFrançois Tigeot } 19385718399fSFrançois Tigeot connector = obj_to_connector(obj); 19395718399fSFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 19405718399fSFrançois Tigeot connector->base.id, 19415718399fSFrançois Tigeot drm_get_connector_name(connector)); 19425718399fSFrançois Tigeot 19435718399fSFrançois Tigeot connector_set[i] = connector; 19445718399fSFrançois Tigeot } 19455718399fSFrançois Tigeot } 19465718399fSFrançois Tigeot 19475718399fSFrançois Tigeot set.crtc = crtc; 19485718399fSFrançois Tigeot set.x = crtc_req->x; 19495718399fSFrançois Tigeot set.y = crtc_req->y; 19505718399fSFrançois Tigeot set.mode = mode; 19515718399fSFrançois Tigeot set.connectors = connector_set; 19525718399fSFrançois Tigeot set.num_connectors = crtc_req->count_connectors; 19535718399fSFrançois Tigeot set.fb = fb; 19545718399fSFrançois Tigeot ret = crtc->funcs->set_config(&set); 19555718399fSFrançois Tigeot 19565718399fSFrançois Tigeot out: 19575718399fSFrançois Tigeot drm_free(connector_set, DRM_MEM_KMS); 19585718399fSFrançois Tigeot drm_mode_destroy(dev, mode); 19595718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 19605718399fSFrançois Tigeot return ret; 19615718399fSFrançois Tigeot } 19625718399fSFrançois Tigeot 19635718399fSFrançois Tigeot int drm_mode_cursor_ioctl(struct drm_device *dev, 19645718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 19655718399fSFrançois Tigeot { 19665718399fSFrançois Tigeot struct drm_mode_cursor *req = data; 19675718399fSFrançois Tigeot struct drm_mode_object *obj; 19685718399fSFrançois Tigeot struct drm_crtc *crtc; 19695718399fSFrançois Tigeot int ret = 0; 19705718399fSFrançois Tigeot 19715718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 19725718399fSFrançois Tigeot return (EINVAL); 19735718399fSFrançois Tigeot 19745718399fSFrançois Tigeot if (!req->flags) 19755718399fSFrançois Tigeot return (EINVAL); 19765718399fSFrançois Tigeot 19775718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 19785718399fSFrançois Tigeot obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); 19795718399fSFrançois Tigeot if (!obj) { 19805718399fSFrançois Tigeot DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 19815718399fSFrançois Tigeot ret = EINVAL; 19825718399fSFrançois Tigeot goto out; 19835718399fSFrançois Tigeot } 19845718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 19855718399fSFrançois Tigeot 19865718399fSFrançois Tigeot if (req->flags & DRM_MODE_CURSOR_BO) { 19875718399fSFrançois Tigeot if (!crtc->funcs->cursor_set) { 19885718399fSFrançois Tigeot ret = ENXIO; 19895718399fSFrançois Tigeot goto out; 19905718399fSFrançois Tigeot } 19915718399fSFrançois Tigeot /* Turns off the cursor if handle is 0 */ 19925718399fSFrançois Tigeot ret = -crtc->funcs->cursor_set(crtc, file_priv, req->handle, 19935718399fSFrançois Tigeot req->width, req->height); 19945718399fSFrançois Tigeot } 19955718399fSFrançois Tigeot 19965718399fSFrançois Tigeot if (req->flags & DRM_MODE_CURSOR_MOVE) { 19975718399fSFrançois Tigeot if (crtc->funcs->cursor_move) { 19985718399fSFrançois Tigeot ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 19995718399fSFrançois Tigeot } else { 20005718399fSFrançois Tigeot ret = EFAULT; 20015718399fSFrançois Tigeot goto out; 20025718399fSFrançois Tigeot } 20035718399fSFrançois Tigeot } 20045718399fSFrançois Tigeot out: 20055718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 20065718399fSFrançois Tigeot return ret; 20075718399fSFrançois Tigeot } 20085718399fSFrançois Tigeot 20095718399fSFrançois Tigeot /* Original addfb only supported RGB formats, so figure out which one */ 20105718399fSFrançois Tigeot uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 20115718399fSFrançois Tigeot { 20125718399fSFrançois Tigeot uint32_t fmt; 20135718399fSFrançois Tigeot 20145718399fSFrançois Tigeot switch (bpp) { 20155718399fSFrançois Tigeot case 8: 20165718399fSFrançois Tigeot fmt = DRM_FORMAT_RGB332; 20175718399fSFrançois Tigeot break; 20185718399fSFrançois Tigeot case 16: 20195718399fSFrançois Tigeot if (depth == 15) 20205718399fSFrançois Tigeot fmt = DRM_FORMAT_XRGB1555; 20215718399fSFrançois Tigeot else 20225718399fSFrançois Tigeot fmt = DRM_FORMAT_RGB565; 20235718399fSFrançois Tigeot break; 20245718399fSFrançois Tigeot case 24: 20255718399fSFrançois Tigeot fmt = DRM_FORMAT_RGB888; 20265718399fSFrançois Tigeot break; 20275718399fSFrançois Tigeot case 32: 20285718399fSFrançois Tigeot if (depth == 24) 20295718399fSFrançois Tigeot fmt = DRM_FORMAT_XRGB8888; 20305718399fSFrançois Tigeot else if (depth == 30) 20315718399fSFrançois Tigeot fmt = DRM_FORMAT_XRGB2101010; 20325718399fSFrançois Tigeot else 20335718399fSFrançois Tigeot fmt = DRM_FORMAT_ARGB8888; 20345718399fSFrançois Tigeot break; 20355718399fSFrançois Tigeot default: 20365718399fSFrançois Tigeot DRM_ERROR("bad bpp, assuming RGB24 pixel format\n"); 20375718399fSFrançois Tigeot fmt = DRM_FORMAT_XRGB8888; 20385718399fSFrançois Tigeot break; 20395718399fSFrançois Tigeot } 20405718399fSFrançois Tigeot 20415718399fSFrançois Tigeot return fmt; 20425718399fSFrançois Tigeot } 20435718399fSFrançois Tigeot 20445718399fSFrançois Tigeot /** 20455718399fSFrançois Tigeot * drm_mode_addfb - add an FB to the graphics configuration 20465718399fSFrançois Tigeot * @inode: inode from the ioctl 20475718399fSFrançois Tigeot * @filp: file * from the ioctl 20485718399fSFrançois Tigeot * @cmd: cmd from ioctl 20495718399fSFrançois Tigeot * @arg: arg from ioctl 20505718399fSFrançois Tigeot * 20515718399fSFrançois Tigeot * LOCKING: 20525718399fSFrançois Tigeot * Takes mode config lock. 20535718399fSFrançois Tigeot * 20545718399fSFrançois Tigeot * Add a new FB to the specified CRTC, given a user request. 20555718399fSFrançois Tigeot * 20565718399fSFrançois Tigeot * Called by the user via ioctl. 20575718399fSFrançois Tigeot * 20585718399fSFrançois Tigeot * RETURNS: 20595718399fSFrançois Tigeot * Zero on success, errno on failure. 20605718399fSFrançois Tigeot */ 20615718399fSFrançois Tigeot int drm_mode_addfb(struct drm_device *dev, 20625718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 20635718399fSFrançois Tigeot { 20645718399fSFrançois Tigeot struct drm_mode_fb_cmd *or = data; 20655718399fSFrançois Tigeot struct drm_mode_fb_cmd2 r = {}; 20665718399fSFrançois Tigeot struct drm_mode_config *config = &dev->mode_config; 20675718399fSFrançois Tigeot struct drm_framebuffer *fb; 20685718399fSFrançois Tigeot int ret = 0; 20695718399fSFrançois Tigeot 20705718399fSFrançois Tigeot /* Use new struct with format internally */ 20715718399fSFrançois Tigeot r.fb_id = or->fb_id; 20725718399fSFrançois Tigeot r.width = or->width; 20735718399fSFrançois Tigeot r.height = or->height; 20745718399fSFrançois Tigeot r.pitches[0] = or->pitch; 20755718399fSFrançois Tigeot r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 20765718399fSFrançois Tigeot r.handles[0] = or->handle; 20775718399fSFrançois Tigeot 20785718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 20795718399fSFrançois Tigeot return (EINVAL); 20805718399fSFrançois Tigeot 20815718399fSFrançois Tigeot if ((config->min_width > r.width) || (r.width > config->max_width)) 20825718399fSFrançois Tigeot return (EINVAL); 20835718399fSFrançois Tigeot if ((config->min_height > r.height) || (r.height > config->max_height)) 20845718399fSFrançois Tigeot return (EINVAL); 20855718399fSFrançois Tigeot 20865718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 20875718399fSFrançois Tigeot 20885718399fSFrançois Tigeot ret = -dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb); 20895718399fSFrançois Tigeot if (ret != 0) { 20905718399fSFrançois Tigeot DRM_ERROR("could not create framebuffer, error %d\n", ret); 20915718399fSFrançois Tigeot goto out; 20925718399fSFrançois Tigeot } 20935718399fSFrançois Tigeot 20945718399fSFrançois Tigeot or->fb_id = fb->base.id; 20955718399fSFrançois Tigeot list_add(&fb->filp_head, &file_priv->fbs); 20965718399fSFrançois Tigeot DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 20975718399fSFrançois Tigeot 20985718399fSFrançois Tigeot out: 20995718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 21005718399fSFrançois Tigeot return ret; 21015718399fSFrançois Tigeot } 21025718399fSFrançois Tigeot 21035718399fSFrançois Tigeot static int format_check(struct drm_mode_fb_cmd2 *r) 21045718399fSFrançois Tigeot { 21055718399fSFrançois Tigeot uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 21065718399fSFrançois Tigeot 21075718399fSFrançois Tigeot switch (format) { 21085718399fSFrançois Tigeot case DRM_FORMAT_C8: 21095718399fSFrançois Tigeot case DRM_FORMAT_RGB332: 21105718399fSFrançois Tigeot case DRM_FORMAT_BGR233: 21115718399fSFrançois Tigeot case DRM_FORMAT_XRGB4444: 21125718399fSFrançois Tigeot case DRM_FORMAT_XBGR4444: 21135718399fSFrançois Tigeot case DRM_FORMAT_RGBX4444: 21145718399fSFrançois Tigeot case DRM_FORMAT_BGRX4444: 21155718399fSFrançois Tigeot case DRM_FORMAT_ARGB4444: 21165718399fSFrançois Tigeot case DRM_FORMAT_ABGR4444: 21175718399fSFrançois Tigeot case DRM_FORMAT_RGBA4444: 21185718399fSFrançois Tigeot case DRM_FORMAT_BGRA4444: 21195718399fSFrançois Tigeot case DRM_FORMAT_XRGB1555: 21205718399fSFrançois Tigeot case DRM_FORMAT_XBGR1555: 21215718399fSFrançois Tigeot case DRM_FORMAT_RGBX5551: 21225718399fSFrançois Tigeot case DRM_FORMAT_BGRX5551: 21235718399fSFrançois Tigeot case DRM_FORMAT_ARGB1555: 21245718399fSFrançois Tigeot case DRM_FORMAT_ABGR1555: 21255718399fSFrançois Tigeot case DRM_FORMAT_RGBA5551: 21265718399fSFrançois Tigeot case DRM_FORMAT_BGRA5551: 21275718399fSFrançois Tigeot case DRM_FORMAT_RGB565: 21285718399fSFrançois Tigeot case DRM_FORMAT_BGR565: 21295718399fSFrançois Tigeot case DRM_FORMAT_RGB888: 21305718399fSFrançois Tigeot case DRM_FORMAT_BGR888: 21315718399fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 21325718399fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 21335718399fSFrançois Tigeot case DRM_FORMAT_RGBX8888: 21345718399fSFrançois Tigeot case DRM_FORMAT_BGRX8888: 21355718399fSFrançois Tigeot case DRM_FORMAT_ARGB8888: 21365718399fSFrançois Tigeot case DRM_FORMAT_ABGR8888: 21375718399fSFrançois Tigeot case DRM_FORMAT_RGBA8888: 21385718399fSFrançois Tigeot case DRM_FORMAT_BGRA8888: 21395718399fSFrançois Tigeot case DRM_FORMAT_XRGB2101010: 21405718399fSFrançois Tigeot case DRM_FORMAT_XBGR2101010: 21415718399fSFrançois Tigeot case DRM_FORMAT_RGBX1010102: 21425718399fSFrançois Tigeot case DRM_FORMAT_BGRX1010102: 21435718399fSFrançois Tigeot case DRM_FORMAT_ARGB2101010: 21445718399fSFrançois Tigeot case DRM_FORMAT_ABGR2101010: 21455718399fSFrançois Tigeot case DRM_FORMAT_RGBA1010102: 21465718399fSFrançois Tigeot case DRM_FORMAT_BGRA1010102: 21475718399fSFrançois Tigeot case DRM_FORMAT_YUYV: 21485718399fSFrançois Tigeot case DRM_FORMAT_YVYU: 21495718399fSFrançois Tigeot case DRM_FORMAT_UYVY: 21505718399fSFrançois Tigeot case DRM_FORMAT_VYUY: 21515718399fSFrançois Tigeot case DRM_FORMAT_AYUV: 21525718399fSFrançois Tigeot case DRM_FORMAT_NV12: 21535718399fSFrançois Tigeot case DRM_FORMAT_NV21: 21545718399fSFrançois Tigeot case DRM_FORMAT_NV16: 21555718399fSFrançois Tigeot case DRM_FORMAT_NV61: 21565718399fSFrançois Tigeot case DRM_FORMAT_YUV410: 21575718399fSFrançois Tigeot case DRM_FORMAT_YVU410: 21585718399fSFrançois Tigeot case DRM_FORMAT_YUV411: 21595718399fSFrançois Tigeot case DRM_FORMAT_YVU411: 21605718399fSFrançois Tigeot case DRM_FORMAT_YUV420: 21615718399fSFrançois Tigeot case DRM_FORMAT_YVU420: 21625718399fSFrançois Tigeot case DRM_FORMAT_YUV422: 21635718399fSFrançois Tigeot case DRM_FORMAT_YVU422: 21645718399fSFrançois Tigeot case DRM_FORMAT_YUV444: 21655718399fSFrançois Tigeot case DRM_FORMAT_YVU444: 21665718399fSFrançois Tigeot return 0; 21675718399fSFrançois Tigeot default: 21685718399fSFrançois Tigeot return (EINVAL); 21695718399fSFrançois Tigeot } 21705718399fSFrançois Tigeot } 21715718399fSFrançois Tigeot 21725718399fSFrançois Tigeot /** 21735718399fSFrançois Tigeot * drm_mode_addfb2 - add an FB to the graphics configuration 21745718399fSFrançois Tigeot * @inode: inode from the ioctl 21755718399fSFrançois Tigeot * @filp: file * from the ioctl 21765718399fSFrançois Tigeot * @cmd: cmd from ioctl 21775718399fSFrançois Tigeot * @arg: arg from ioctl 21785718399fSFrançois Tigeot * 21795718399fSFrançois Tigeot * LOCKING: 21805718399fSFrançois Tigeot * Takes mode config lock. 21815718399fSFrançois Tigeot * 21825718399fSFrançois Tigeot * Add a new FB to the specified CRTC, given a user request with format. 21835718399fSFrançois Tigeot * 21845718399fSFrançois Tigeot * Called by the user via ioctl. 21855718399fSFrançois Tigeot * 21865718399fSFrançois Tigeot * RETURNS: 21875718399fSFrançois Tigeot * Zero on success, errno on failure. 21885718399fSFrançois Tigeot */ 21895718399fSFrançois Tigeot int drm_mode_addfb2(struct drm_device *dev, 21905718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 21915718399fSFrançois Tigeot { 21925718399fSFrançois Tigeot struct drm_mode_fb_cmd2 *r = data; 21935718399fSFrançois Tigeot struct drm_mode_config *config = &dev->mode_config; 21945718399fSFrançois Tigeot struct drm_framebuffer *fb; 21955718399fSFrançois Tigeot int ret = 0; 21965718399fSFrançois Tigeot 21975718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 21985718399fSFrançois Tigeot return (EINVAL); 21995718399fSFrançois Tigeot 22005718399fSFrançois Tigeot if ((config->min_width > r->width) || (r->width > config->max_width)) { 22015718399fSFrançois Tigeot DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", 22025718399fSFrançois Tigeot r->width, config->min_width, config->max_width); 22035718399fSFrançois Tigeot return (EINVAL); 22045718399fSFrançois Tigeot } 22055718399fSFrançois Tigeot if ((config->min_height > r->height) || (r->height > config->max_height)) { 22065718399fSFrançois Tigeot DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", 22075718399fSFrançois Tigeot r->height, config->min_height, config->max_height); 22085718399fSFrançois Tigeot return (EINVAL); 22095718399fSFrançois Tigeot } 22105718399fSFrançois Tigeot 22115718399fSFrançois Tigeot ret = format_check(r); 22125718399fSFrançois Tigeot if (ret) { 22135718399fSFrançois Tigeot DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format); 22145718399fSFrançois Tigeot return ret; 22155718399fSFrançois Tigeot } 22165718399fSFrançois Tigeot 22175718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 22185718399fSFrançois Tigeot 22195718399fSFrançois Tigeot /* TODO check buffer is sufficiently large */ 22205718399fSFrançois Tigeot /* TODO setup destructor callback */ 22215718399fSFrançois Tigeot 22225718399fSFrançois Tigeot ret = -dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb); 22235718399fSFrançois Tigeot if (ret != 0) { 22245718399fSFrançois Tigeot DRM_ERROR("could not create framebuffer, error %d\n", ret); 22255718399fSFrançois Tigeot goto out; 22265718399fSFrançois Tigeot } 22275718399fSFrançois Tigeot 22285718399fSFrançois Tigeot r->fb_id = fb->base.id; 22295718399fSFrançois Tigeot list_add(&fb->filp_head, &file_priv->fbs); 22305718399fSFrançois Tigeot DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 22315718399fSFrançois Tigeot 22325718399fSFrançois Tigeot out: 22335718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 22345718399fSFrançois Tigeot return (ret); 22355718399fSFrançois Tigeot } 22365718399fSFrançois Tigeot 22375718399fSFrançois Tigeot /** 22385718399fSFrançois Tigeot * drm_mode_rmfb - remove an FB from the configuration 22395718399fSFrançois Tigeot * @inode: inode from the ioctl 22405718399fSFrançois Tigeot * @filp: file * from the ioctl 22415718399fSFrançois Tigeot * @cmd: cmd from ioctl 22425718399fSFrançois Tigeot * @arg: arg from ioctl 22435718399fSFrançois Tigeot * 22445718399fSFrançois Tigeot * LOCKING: 22455718399fSFrançois Tigeot * Takes mode config lock. 22465718399fSFrançois Tigeot * 22475718399fSFrançois Tigeot * Remove the FB specified by the user. 22485718399fSFrançois Tigeot * 22495718399fSFrançois Tigeot * Called by the user via ioctl. 22505718399fSFrançois Tigeot * 22515718399fSFrançois Tigeot * RETURNS: 22525718399fSFrançois Tigeot * Zero on success, errno on failure. 22535718399fSFrançois Tigeot */ 22545718399fSFrançois Tigeot int drm_mode_rmfb(struct drm_device *dev, 22555718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 22565718399fSFrançois Tigeot { 22575718399fSFrançois Tigeot struct drm_mode_object *obj; 22585718399fSFrançois Tigeot struct drm_framebuffer *fb = NULL; 22595718399fSFrançois Tigeot struct drm_framebuffer *fbl = NULL; 22605718399fSFrançois Tigeot uint32_t *id = data; 22615718399fSFrançois Tigeot int ret = 0; 22625718399fSFrançois Tigeot int found = 0; 22635718399fSFrançois Tigeot 22645718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22655718399fSFrançois Tigeot return (EINVAL); 22665718399fSFrançois Tigeot 22675718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 22685718399fSFrançois Tigeot obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); 22695718399fSFrançois Tigeot /* TODO check that we really get a framebuffer back. */ 22705718399fSFrançois Tigeot if (!obj) { 22715718399fSFrançois Tigeot ret = EINVAL; 22725718399fSFrançois Tigeot goto out; 22735718399fSFrançois Tigeot } 22745718399fSFrançois Tigeot fb = obj_to_fb(obj); 22755718399fSFrançois Tigeot 22765718399fSFrançois Tigeot list_for_each_entry(fbl, &file_priv->fbs, filp_head) 22775718399fSFrançois Tigeot if (fb == fbl) 22785718399fSFrançois Tigeot found = 1; 22795718399fSFrançois Tigeot 22805718399fSFrançois Tigeot if (!found) { 22815718399fSFrançois Tigeot ret = EINVAL; 22825718399fSFrançois Tigeot goto out; 22835718399fSFrançois Tigeot } 22845718399fSFrançois Tigeot 22855718399fSFrançois Tigeot /* TODO release all crtc connected to the framebuffer */ 22865718399fSFrançois Tigeot /* TODO unhock the destructor from the buffer object */ 22875718399fSFrançois Tigeot 22885718399fSFrançois Tigeot list_del(&fb->filp_head); 22895718399fSFrançois Tigeot fb->funcs->destroy(fb); 22905718399fSFrançois Tigeot 22915718399fSFrançois Tigeot out: 22925718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 22935718399fSFrançois Tigeot return ret; 22945718399fSFrançois Tigeot } 22955718399fSFrançois Tigeot 22965718399fSFrançois Tigeot /** 22975718399fSFrançois Tigeot * drm_mode_getfb - get FB info 22985718399fSFrançois Tigeot * @inode: inode from the ioctl 22995718399fSFrançois Tigeot * @filp: file * from the ioctl 23005718399fSFrançois Tigeot * @cmd: cmd from ioctl 23015718399fSFrançois Tigeot * @arg: arg from ioctl 23025718399fSFrançois Tigeot * 23035718399fSFrançois Tigeot * LOCKING: 23045718399fSFrançois Tigeot * Takes mode config lock. 23055718399fSFrançois Tigeot * 23065718399fSFrançois Tigeot * Lookup the FB given its ID and return info about it. 23075718399fSFrançois Tigeot * 23085718399fSFrançois Tigeot * Called by the user via ioctl. 23095718399fSFrançois Tigeot * 23105718399fSFrançois Tigeot * RETURNS: 23115718399fSFrançois Tigeot * Zero on success, errno on failure. 23125718399fSFrançois Tigeot */ 23135718399fSFrançois Tigeot int drm_mode_getfb(struct drm_device *dev, 23145718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 23155718399fSFrançois Tigeot { 23165718399fSFrançois Tigeot struct drm_mode_fb_cmd *r = data; 23175718399fSFrançois Tigeot struct drm_mode_object *obj; 23185718399fSFrançois Tigeot struct drm_framebuffer *fb; 23195718399fSFrançois Tigeot int ret = 0; 23205718399fSFrançois Tigeot 23215718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23225718399fSFrançois Tigeot return (EINVAL); 23235718399fSFrançois Tigeot 23245718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 23255718399fSFrançois Tigeot obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 23265718399fSFrançois Tigeot if (!obj) { 23275718399fSFrançois Tigeot ret = EINVAL; 23285718399fSFrançois Tigeot goto out; 23295718399fSFrançois Tigeot } 23305718399fSFrançois Tigeot fb = obj_to_fb(obj); 23315718399fSFrançois Tigeot 23325718399fSFrançois Tigeot r->height = fb->height; 23335718399fSFrançois Tigeot r->width = fb->width; 23345718399fSFrançois Tigeot r->depth = fb->depth; 23355718399fSFrançois Tigeot r->bpp = fb->bits_per_pixel; 23365718399fSFrançois Tigeot r->pitch = fb->pitches[0]; 23375718399fSFrançois Tigeot fb->funcs->create_handle(fb, file_priv, &r->handle); 23385718399fSFrançois Tigeot 23395718399fSFrançois Tigeot out: 23405718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 23415718399fSFrançois Tigeot return ret; 23425718399fSFrançois Tigeot } 23435718399fSFrançois Tigeot 23445718399fSFrançois Tigeot int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 23455718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 23465718399fSFrançois Tigeot { 23475718399fSFrançois Tigeot struct drm_clip_rect __user *clips_ptr; 23485718399fSFrançois Tigeot struct drm_clip_rect *clips = NULL; 23495718399fSFrançois Tigeot struct drm_mode_fb_dirty_cmd *r = data; 23505718399fSFrançois Tigeot struct drm_mode_object *obj; 23515718399fSFrançois Tigeot struct drm_framebuffer *fb; 23525718399fSFrançois Tigeot unsigned flags; 23535718399fSFrançois Tigeot int num_clips; 23545718399fSFrançois Tigeot int ret = 0; 23555718399fSFrançois Tigeot 23565718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23575718399fSFrançois Tigeot return (EINVAL); 23585718399fSFrançois Tigeot 23595718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 23605718399fSFrançois Tigeot obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 23615718399fSFrançois Tigeot if (!obj) { 23625718399fSFrançois Tigeot ret = EINVAL; 23635718399fSFrançois Tigeot goto out_err1; 23645718399fSFrançois Tigeot } 23655718399fSFrançois Tigeot fb = obj_to_fb(obj); 23665718399fSFrançois Tigeot 23675718399fSFrançois Tigeot num_clips = r->num_clips; 23685718399fSFrançois Tigeot clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr; 23695718399fSFrançois Tigeot 23705718399fSFrançois Tigeot if (!num_clips != !clips_ptr) { 23715718399fSFrançois Tigeot ret = EINVAL; 23725718399fSFrançois Tigeot goto out_err1; 23735718399fSFrançois Tigeot } 23745718399fSFrançois Tigeot 23755718399fSFrançois Tigeot flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 23765718399fSFrançois Tigeot 23775718399fSFrançois Tigeot /* If userspace annotates copy, clips must come in pairs */ 23785718399fSFrançois Tigeot if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 23795718399fSFrançois Tigeot ret = EINVAL; 23805718399fSFrançois Tigeot goto out_err1; 23815718399fSFrançois Tigeot } 23825718399fSFrançois Tigeot 23835718399fSFrançois Tigeot if (num_clips && clips_ptr) { 23845718399fSFrançois Tigeot if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 23855718399fSFrançois Tigeot ret = EINVAL; 23865718399fSFrançois Tigeot goto out_err1; 23875718399fSFrançois Tigeot } 23885718399fSFrançois Tigeot clips = kmalloc(num_clips * sizeof(*clips), DRM_MEM_KMS, 23895718399fSFrançois Tigeot M_WAITOK | M_ZERO); 23905718399fSFrançois Tigeot 23915718399fSFrançois Tigeot ret = copyin(clips_ptr, clips, num_clips * sizeof(*clips)); 23925718399fSFrançois Tigeot if (ret) 23935718399fSFrançois Tigeot goto out_err2; 23945718399fSFrançois Tigeot } 23955718399fSFrançois Tigeot 23965718399fSFrançois Tigeot if (fb->funcs->dirty) { 23975718399fSFrançois Tigeot ret = -fb->funcs->dirty(fb, file_priv, flags, r->color, 23985718399fSFrançois Tigeot clips, num_clips); 23995718399fSFrançois Tigeot } else { 24005718399fSFrançois Tigeot ret = ENOSYS; 24015718399fSFrançois Tigeot goto out_err2; 24025718399fSFrançois Tigeot } 24035718399fSFrançois Tigeot 24045718399fSFrançois Tigeot out_err2: 24055718399fSFrançois Tigeot drm_free(clips, DRM_MEM_KMS); 24065718399fSFrançois Tigeot out_err1: 24075718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 24085718399fSFrançois Tigeot return ret; 24095718399fSFrançois Tigeot } 24105718399fSFrançois Tigeot 24115718399fSFrançois Tigeot 24125718399fSFrançois Tigeot /** 24135718399fSFrançois Tigeot * drm_fb_release - remove and free the FBs on this file 24145718399fSFrançois Tigeot * @filp: file * from the ioctl 24155718399fSFrançois Tigeot * 24165718399fSFrançois Tigeot * LOCKING: 24175718399fSFrançois Tigeot * Takes mode config lock. 24185718399fSFrançois Tigeot * 24195718399fSFrançois Tigeot * Destroy all the FBs associated with @filp. 24205718399fSFrançois Tigeot * 24215718399fSFrançois Tigeot * Called by the user via ioctl. 24225718399fSFrançois Tigeot * 24235718399fSFrançois Tigeot * RETURNS: 24245718399fSFrançois Tigeot * Zero on success, errno on failure. 24255718399fSFrançois Tigeot */ 24265718399fSFrançois Tigeot void drm_fb_release(struct drm_file *priv) 24275718399fSFrançois Tigeot { 24285718399fSFrançois Tigeot #if 1 24295718399fSFrançois Tigeot struct drm_device *dev = priv->dev; 24305718399fSFrançois Tigeot #else 24315718399fSFrançois Tigeot struct drm_device *dev = priv->minor->dev; 24325718399fSFrançois Tigeot #endif 24335718399fSFrançois Tigeot struct drm_framebuffer *fb, *tfb; 24345718399fSFrançois Tigeot 24355718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 24365718399fSFrançois Tigeot list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 24375718399fSFrançois Tigeot list_del(&fb->filp_head); 24385718399fSFrançois Tigeot fb->funcs->destroy(fb); 24395718399fSFrançois Tigeot } 24405718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 24415718399fSFrançois Tigeot } 24425718399fSFrançois Tigeot 24435718399fSFrançois Tigeot /** 24445718399fSFrançois Tigeot * drm_mode_attachmode - add a mode to the user mode list 24455718399fSFrançois Tigeot * @dev: DRM device 24465718399fSFrançois Tigeot * @connector: connector to add the mode to 24475718399fSFrançois Tigeot * @mode: mode to add 24485718399fSFrançois Tigeot * 24495718399fSFrançois Tigeot * Add @mode to @connector's user mode list. 24505718399fSFrançois Tigeot */ 24515718399fSFrançois Tigeot static void drm_mode_attachmode(struct drm_device *dev, 24525718399fSFrançois Tigeot struct drm_connector *connector, 24535718399fSFrançois Tigeot struct drm_display_mode *mode) 24545718399fSFrançois Tigeot { 24555718399fSFrançois Tigeot list_add_tail(&mode->head, &connector->user_modes); 24565718399fSFrançois Tigeot } 24575718399fSFrançois Tigeot 24585718399fSFrançois Tigeot int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, 24595718399fSFrançois Tigeot const struct drm_display_mode *mode) 24605718399fSFrançois Tigeot { 24615718399fSFrançois Tigeot struct drm_connector *connector; 24625718399fSFrançois Tigeot int ret = 0; 24635718399fSFrançois Tigeot struct drm_display_mode *dup_mode, *next; 24645718399fSFrançois Tigeot DRM_LIST_HEAD(list); 24655718399fSFrançois Tigeot 24665718399fSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 24675718399fSFrançois Tigeot if (!connector->encoder) 24685718399fSFrançois Tigeot continue; 24695718399fSFrançois Tigeot if (connector->encoder->crtc == crtc) { 24705718399fSFrançois Tigeot dup_mode = drm_mode_duplicate(dev, mode); 24715718399fSFrançois Tigeot if (!dup_mode) { 24725718399fSFrançois Tigeot ret = ENOMEM; 24735718399fSFrançois Tigeot goto out; 24745718399fSFrançois Tigeot } 24755718399fSFrançois Tigeot list_add_tail(&dup_mode->head, &list); 24765718399fSFrançois Tigeot } 24775718399fSFrançois Tigeot } 24785718399fSFrançois Tigeot 24795718399fSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 24805718399fSFrançois Tigeot if (!connector->encoder) 24815718399fSFrançois Tigeot continue; 24825718399fSFrançois Tigeot if (connector->encoder->crtc == crtc) 24835718399fSFrançois Tigeot list_move_tail(list.next, &connector->user_modes); 24845718399fSFrançois Tigeot } 24855718399fSFrançois Tigeot 24865718399fSFrançois Tigeot KASSERT(!list_empty(&list), ("list empty")); 24875718399fSFrançois Tigeot 24885718399fSFrançois Tigeot out: 24895718399fSFrançois Tigeot list_for_each_entry_safe(dup_mode, next, &list, head) 24905718399fSFrançois Tigeot drm_mode_destroy(dev, dup_mode); 24915718399fSFrançois Tigeot 24925718399fSFrançois Tigeot return ret; 24935718399fSFrançois Tigeot } 24945718399fSFrançois Tigeot 24955718399fSFrançois Tigeot static int drm_mode_detachmode(struct drm_device *dev, 24965718399fSFrançois Tigeot struct drm_connector *connector, 24975718399fSFrançois Tigeot struct drm_display_mode *mode) 24985718399fSFrançois Tigeot { 24995718399fSFrançois Tigeot int found = 0; 25005718399fSFrançois Tigeot int ret = 0; 25015718399fSFrançois Tigeot struct drm_display_mode *match_mode, *t; 25025718399fSFrançois Tigeot 25035718399fSFrançois Tigeot list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { 25045718399fSFrançois Tigeot if (drm_mode_equal(match_mode, mode)) { 25055718399fSFrançois Tigeot list_del(&match_mode->head); 25065718399fSFrançois Tigeot drm_mode_destroy(dev, match_mode); 25075718399fSFrançois Tigeot found = 1; 25085718399fSFrançois Tigeot break; 25095718399fSFrançois Tigeot } 25105718399fSFrançois Tigeot } 25115718399fSFrançois Tigeot 25125718399fSFrançois Tigeot if (!found) 25135718399fSFrançois Tigeot ret = -EINVAL; 25145718399fSFrançois Tigeot 25155718399fSFrançois Tigeot return ret; 25165718399fSFrançois Tigeot } 25175718399fSFrançois Tigeot 25185718399fSFrançois Tigeot int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) 25195718399fSFrançois Tigeot { 25205718399fSFrançois Tigeot struct drm_connector *connector; 25215718399fSFrançois Tigeot 25225718399fSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 25235718399fSFrançois Tigeot drm_mode_detachmode(dev, connector, mode); 25245718399fSFrançois Tigeot } 25255718399fSFrançois Tigeot return 0; 25265718399fSFrançois Tigeot } 25275718399fSFrançois Tigeot 25285718399fSFrançois Tigeot /** 25295718399fSFrançois Tigeot * drm_fb_attachmode - Attach a user mode to an connector 25305718399fSFrançois Tigeot * @inode: inode from the ioctl 25315718399fSFrançois Tigeot * @filp: file * from the ioctl 25325718399fSFrançois Tigeot * @cmd: cmd from ioctl 25335718399fSFrançois Tigeot * @arg: arg from ioctl 25345718399fSFrançois Tigeot * 25355718399fSFrançois Tigeot * This attaches a user specified mode to an connector. 25365718399fSFrançois Tigeot * Called by the user via ioctl. 25375718399fSFrançois Tigeot * 25385718399fSFrançois Tigeot * RETURNS: 25395718399fSFrançois Tigeot * Zero on success, errno on failure. 25405718399fSFrançois Tigeot */ 25415718399fSFrançois Tigeot int drm_mode_attachmode_ioctl(struct drm_device *dev, 25425718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 25435718399fSFrançois Tigeot { 25445718399fSFrançois Tigeot struct drm_mode_mode_cmd *mode_cmd = data; 25455718399fSFrançois Tigeot struct drm_connector *connector; 25465718399fSFrançois Tigeot struct drm_display_mode *mode; 25475718399fSFrançois Tigeot struct drm_mode_object *obj; 25485718399fSFrançois Tigeot struct drm_mode_modeinfo *umode = &mode_cmd->mode; 25495718399fSFrançois Tigeot int ret = 0; 25505718399fSFrançois Tigeot 25515718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 25525718399fSFrançois Tigeot return -EINVAL; 25535718399fSFrançois Tigeot 25545718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 25555718399fSFrançois Tigeot 25565718399fSFrançois Tigeot obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); 25575718399fSFrançois Tigeot if (!obj) { 25585718399fSFrançois Tigeot ret = -EINVAL; 25595718399fSFrançois Tigeot goto out; 25605718399fSFrançois Tigeot } 25615718399fSFrançois Tigeot connector = obj_to_connector(obj); 25625718399fSFrançois Tigeot 25635718399fSFrançois Tigeot mode = drm_mode_create(dev); 25645718399fSFrançois Tigeot if (!mode) { 25655718399fSFrançois Tigeot ret = -ENOMEM; 25665718399fSFrançois Tigeot goto out; 25675718399fSFrançois Tigeot } 25685718399fSFrançois Tigeot 25695718399fSFrançois Tigeot ret = drm_crtc_convert_umode(mode, umode); 25705718399fSFrançois Tigeot if (ret) { 25715718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid mode\n"); 25725718399fSFrançois Tigeot drm_mode_destroy(dev, mode); 25735718399fSFrançois Tigeot goto out; 25745718399fSFrançois Tigeot } 25755718399fSFrançois Tigeot 25765718399fSFrançois Tigeot drm_mode_attachmode(dev, connector, mode); 25775718399fSFrançois Tigeot out: 25785718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 25795718399fSFrançois Tigeot return ret; 25805718399fSFrançois Tigeot } 25815718399fSFrançois Tigeot 25825718399fSFrançois Tigeot 25835718399fSFrançois Tigeot /** 25845718399fSFrançois Tigeot * drm_fb_detachmode - Detach a user specified mode from an connector 25855718399fSFrançois Tigeot * @inode: inode from the ioctl 25865718399fSFrançois Tigeot * @filp: file * from the ioctl 25875718399fSFrançois Tigeot * @cmd: cmd from ioctl 25885718399fSFrançois Tigeot * @arg: arg from ioctl 25895718399fSFrançois Tigeot * 25905718399fSFrançois Tigeot * Called by the user via ioctl. 25915718399fSFrançois Tigeot * 25925718399fSFrançois Tigeot * RETURNS: 25935718399fSFrançois Tigeot * Zero on success, errno on failure. 25945718399fSFrançois Tigeot */ 25955718399fSFrançois Tigeot int drm_mode_detachmode_ioctl(struct drm_device *dev, 25965718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 25975718399fSFrançois Tigeot { 25985718399fSFrançois Tigeot struct drm_mode_object *obj; 25995718399fSFrançois Tigeot struct drm_mode_mode_cmd *mode_cmd = data; 26005718399fSFrançois Tigeot struct drm_connector *connector; 26015718399fSFrançois Tigeot struct drm_display_mode mode; 26025718399fSFrançois Tigeot struct drm_mode_modeinfo *umode = &mode_cmd->mode; 26035718399fSFrançois Tigeot int ret = 0; 26045718399fSFrançois Tigeot 26055718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 26065718399fSFrançois Tigeot return -EINVAL; 26075718399fSFrançois Tigeot 26085718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 26095718399fSFrançois Tigeot 26105718399fSFrançois Tigeot obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); 26115718399fSFrançois Tigeot if (!obj) { 26125718399fSFrançois Tigeot ret = -EINVAL; 26135718399fSFrançois Tigeot goto out; 26145718399fSFrançois Tigeot } 26155718399fSFrançois Tigeot connector = obj_to_connector(obj); 26165718399fSFrançois Tigeot 26175718399fSFrançois Tigeot ret = drm_crtc_convert_umode(&mode, umode); 26185718399fSFrançois Tigeot if (ret) { 26195718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid mode\n"); 26205718399fSFrançois Tigeot goto out; 26215718399fSFrançois Tigeot } 26225718399fSFrançois Tigeot 26235718399fSFrançois Tigeot ret = drm_mode_detachmode(dev, connector, &mode); 26245718399fSFrançois Tigeot out: 26255718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 26265718399fSFrançois Tigeot return ret; 26275718399fSFrançois Tigeot } 26285718399fSFrançois Tigeot 26295718399fSFrançois Tigeot struct drm_property *drm_property_create(struct drm_device *dev, int flags, 26305718399fSFrançois Tigeot const char *name, int num_values) 26315718399fSFrançois Tigeot { 26325718399fSFrançois Tigeot struct drm_property *property = NULL; 26335718399fSFrançois Tigeot int ret; 26345718399fSFrançois Tigeot 26355718399fSFrançois Tigeot property = kmalloc(sizeof(struct drm_property), DRM_MEM_KMS, 26365718399fSFrançois Tigeot M_WAITOK | M_ZERO); 26375718399fSFrançois Tigeot 26385718399fSFrançois Tigeot if (num_values) { 26395718399fSFrançois Tigeot property->values = kmalloc(sizeof(uint64_t)*num_values, DRM_MEM_KMS, 26405718399fSFrançois Tigeot M_WAITOK | M_ZERO); 26415718399fSFrançois Tigeot } 26425718399fSFrançois Tigeot 26435718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 26445718399fSFrançois Tigeot if (ret) 26455718399fSFrançois Tigeot goto fail; 26465718399fSFrançois Tigeot property->flags = flags; 26475718399fSFrançois Tigeot property->num_values = num_values; 26485718399fSFrançois Tigeot INIT_LIST_HEAD(&property->enum_blob_list); 26495718399fSFrançois Tigeot 26505718399fSFrançois Tigeot if (name) { 26515718399fSFrançois Tigeot strncpy(property->name, name, DRM_PROP_NAME_LEN); 26525718399fSFrançois Tigeot property->name[DRM_PROP_NAME_LEN-1] = '\0'; 26535718399fSFrançois Tigeot } 26545718399fSFrançois Tigeot 26555718399fSFrançois Tigeot list_add_tail(&property->head, &dev->mode_config.property_list); 26565718399fSFrançois Tigeot return property; 26575718399fSFrançois Tigeot 26585718399fSFrançois Tigeot fail: 26595718399fSFrançois Tigeot drm_free(property->values, DRM_MEM_KMS); 26605718399fSFrançois Tigeot drm_free(property, DRM_MEM_KMS); 26615718399fSFrançois Tigeot return (NULL); 26625718399fSFrançois Tigeot } 26635718399fSFrançois Tigeot 26645718399fSFrançois Tigeot struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 26655718399fSFrançois Tigeot const char *name, 26665718399fSFrançois Tigeot const struct drm_prop_enum_list *props, 26675718399fSFrançois Tigeot int num_values) 26685718399fSFrançois Tigeot { 26695718399fSFrançois Tigeot struct drm_property *property; 26705718399fSFrançois Tigeot int i, ret; 26715718399fSFrançois Tigeot 26725718399fSFrançois Tigeot flags |= DRM_MODE_PROP_ENUM; 26735718399fSFrançois Tigeot 26745718399fSFrançois Tigeot property = drm_property_create(dev, flags, name, num_values); 26755718399fSFrançois Tigeot if (!property) 26765718399fSFrançois Tigeot return NULL; 26775718399fSFrançois Tigeot 26785718399fSFrançois Tigeot for (i = 0; i < num_values; i++) { 26795718399fSFrançois Tigeot ret = drm_property_add_enum(property, i, 26805718399fSFrançois Tigeot props[i].type, 26815718399fSFrançois Tigeot props[i].name); 26825718399fSFrançois Tigeot if (ret) { 26835718399fSFrançois Tigeot drm_property_destroy(dev, property); 26845718399fSFrançois Tigeot return NULL; 26855718399fSFrançois Tigeot } 26865718399fSFrançois Tigeot } 26875718399fSFrançois Tigeot 26885718399fSFrançois Tigeot return property; 26895718399fSFrançois Tigeot } 26905718399fSFrançois Tigeot 26915718399fSFrançois Tigeot struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 26925718399fSFrançois Tigeot const char *name, 26935718399fSFrançois Tigeot uint64_t min, uint64_t max) 26945718399fSFrançois Tigeot { 26955718399fSFrançois Tigeot struct drm_property *property; 26965718399fSFrançois Tigeot 26975718399fSFrançois Tigeot flags |= DRM_MODE_PROP_RANGE; 26985718399fSFrançois Tigeot 26995718399fSFrançois Tigeot property = drm_property_create(dev, flags, name, 2); 27005718399fSFrançois Tigeot if (!property) 27015718399fSFrançois Tigeot return NULL; 27025718399fSFrançois Tigeot 27035718399fSFrançois Tigeot property->values[0] = min; 27045718399fSFrançois Tigeot property->values[1] = max; 27055718399fSFrançois Tigeot 27065718399fSFrançois Tigeot return property; 27075718399fSFrançois Tigeot } 27085718399fSFrançois Tigeot 27095718399fSFrançois Tigeot int drm_property_add_enum(struct drm_property *property, int index, 27105718399fSFrançois Tigeot uint64_t value, const char *name) 27115718399fSFrançois Tigeot { 27125718399fSFrançois Tigeot struct drm_property_enum *prop_enum; 27135718399fSFrançois Tigeot 27145718399fSFrançois Tigeot if (!(property->flags & DRM_MODE_PROP_ENUM)) 27155718399fSFrançois Tigeot return -EINVAL; 27165718399fSFrançois Tigeot 27175718399fSFrançois Tigeot if (!list_empty(&property->enum_blob_list)) { 27185718399fSFrançois Tigeot list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 27195718399fSFrançois Tigeot if (prop_enum->value == value) { 27205718399fSFrançois Tigeot strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 27215718399fSFrançois Tigeot prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 27225718399fSFrançois Tigeot return 0; 27235718399fSFrançois Tigeot } 27245718399fSFrançois Tigeot } 27255718399fSFrançois Tigeot } 27265718399fSFrançois Tigeot 27275718399fSFrançois Tigeot prop_enum = kmalloc(sizeof(struct drm_property_enum), DRM_MEM_KMS, 27285718399fSFrançois Tigeot M_WAITOK | M_ZERO); 27295718399fSFrançois Tigeot 27305718399fSFrançois Tigeot strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 27315718399fSFrançois Tigeot prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 27325718399fSFrançois Tigeot prop_enum->value = value; 27335718399fSFrançois Tigeot 27345718399fSFrançois Tigeot property->values[index] = value; 27355718399fSFrançois Tigeot list_add_tail(&prop_enum->head, &property->enum_blob_list); 27365718399fSFrançois Tigeot return 0; 27375718399fSFrançois Tigeot } 27385718399fSFrançois Tigeot 27395718399fSFrançois Tigeot void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 27405718399fSFrançois Tigeot { 27415718399fSFrançois Tigeot struct drm_property_enum *prop_enum, *pt; 27425718399fSFrançois Tigeot 27435718399fSFrançois Tigeot list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { 27445718399fSFrançois Tigeot list_del(&prop_enum->head); 27455718399fSFrançois Tigeot drm_free(prop_enum, DRM_MEM_KMS); 27465718399fSFrançois Tigeot } 27475718399fSFrançois Tigeot 27485718399fSFrançois Tigeot if (property->num_values) 27495718399fSFrançois Tigeot drm_free(property->values, DRM_MEM_KMS); 27505718399fSFrançois Tigeot drm_mode_object_put(dev, &property->base); 27515718399fSFrançois Tigeot list_del(&property->head); 27525718399fSFrançois Tigeot drm_free(property, DRM_MEM_KMS); 27535718399fSFrançois Tigeot } 27545718399fSFrançois Tigeot 27555718399fSFrançois Tigeot int drm_connector_attach_property(struct drm_connector *connector, 27565718399fSFrançois Tigeot struct drm_property *property, uint64_t init_val) 27575718399fSFrançois Tigeot { 27585718399fSFrançois Tigeot int i; 27595718399fSFrançois Tigeot 27605718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 27615718399fSFrançois Tigeot if (connector->property_ids[i] == 0) { 27625718399fSFrançois Tigeot connector->property_ids[i] = property->base.id; 27635718399fSFrançois Tigeot connector->property_values[i] = init_val; 27645718399fSFrançois Tigeot break; 27655718399fSFrançois Tigeot } 27665718399fSFrançois Tigeot } 27675718399fSFrançois Tigeot 27685718399fSFrançois Tigeot if (i == DRM_CONNECTOR_MAX_PROPERTY) 27695718399fSFrançois Tigeot return -EINVAL; 27705718399fSFrançois Tigeot return 0; 27715718399fSFrançois Tigeot } 27725718399fSFrançois Tigeot 27735718399fSFrançois Tigeot int drm_connector_property_set_value(struct drm_connector *connector, 27745718399fSFrançois Tigeot struct drm_property *property, uint64_t value) 27755718399fSFrançois Tigeot { 27765718399fSFrançois Tigeot int i; 27775718399fSFrançois Tigeot 27785718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 27795718399fSFrançois Tigeot if (connector->property_ids[i] == property->base.id) { 27805718399fSFrançois Tigeot connector->property_values[i] = value; 27815718399fSFrançois Tigeot break; 27825718399fSFrançois Tigeot } 27835718399fSFrançois Tigeot } 27845718399fSFrançois Tigeot 27855718399fSFrançois Tigeot if (i == DRM_CONNECTOR_MAX_PROPERTY) 27865718399fSFrançois Tigeot return -EINVAL; 27875718399fSFrançois Tigeot return 0; 27885718399fSFrançois Tigeot } 27895718399fSFrançois Tigeot 27905718399fSFrançois Tigeot int drm_connector_property_get_value(struct drm_connector *connector, 27915718399fSFrançois Tigeot struct drm_property *property, uint64_t *val) 27925718399fSFrançois Tigeot { 27935718399fSFrançois Tigeot int i; 27945718399fSFrançois Tigeot 27955718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 27965718399fSFrançois Tigeot if (connector->property_ids[i] == property->base.id) { 27975718399fSFrançois Tigeot *val = connector->property_values[i]; 27985718399fSFrançois Tigeot break; 27995718399fSFrançois Tigeot } 28005718399fSFrançois Tigeot } 28015718399fSFrançois Tigeot 28025718399fSFrançois Tigeot if (i == DRM_CONNECTOR_MAX_PROPERTY) 28035718399fSFrançois Tigeot return -EINVAL; 28045718399fSFrançois Tigeot return 0; 28055718399fSFrançois Tigeot } 28065718399fSFrançois Tigeot 28075718399fSFrançois Tigeot int drm_mode_getproperty_ioctl(struct drm_device *dev, 28085718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 28095718399fSFrançois Tigeot { 28105718399fSFrançois Tigeot struct drm_mode_object *obj; 28115718399fSFrançois Tigeot struct drm_mode_get_property *out_resp = data; 28125718399fSFrançois Tigeot struct drm_property *property; 28135718399fSFrançois Tigeot int enum_count = 0; 28145718399fSFrançois Tigeot int blob_count = 0; 28155718399fSFrançois Tigeot int value_count = 0; 28165718399fSFrançois Tigeot int ret = 0, i; 28175718399fSFrançois Tigeot int copied; 28185718399fSFrançois Tigeot struct drm_property_enum *prop_enum; 28195718399fSFrançois Tigeot struct drm_mode_property_enum __user *enum_ptr; 28205718399fSFrançois Tigeot struct drm_property_blob *prop_blob; 28215718399fSFrançois Tigeot uint32_t *blob_id_ptr; 28225718399fSFrançois Tigeot uint64_t *values_ptr; 28235718399fSFrançois Tigeot uint32_t *blob_length_ptr; 28245718399fSFrançois Tigeot 28255718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 28265718399fSFrançois Tigeot return -EINVAL; 28275718399fSFrançois Tigeot 28285718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 28295718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); 28305718399fSFrançois Tigeot if (!obj) { 28315718399fSFrançois Tigeot ret = -EINVAL; 28325718399fSFrançois Tigeot goto done; 28335718399fSFrançois Tigeot } 28345718399fSFrançois Tigeot property = obj_to_property(obj); 28355718399fSFrançois Tigeot 28365718399fSFrançois Tigeot if (property->flags & DRM_MODE_PROP_ENUM) { 28375718399fSFrançois Tigeot list_for_each_entry(prop_enum, &property->enum_blob_list, head) 28385718399fSFrançois Tigeot enum_count++; 28395718399fSFrançois Tigeot } else if (property->flags & DRM_MODE_PROP_BLOB) { 28405718399fSFrançois Tigeot list_for_each_entry(prop_blob, &property->enum_blob_list, head) 28415718399fSFrançois Tigeot blob_count++; 28425718399fSFrançois Tigeot } 28435718399fSFrançois Tigeot 28445718399fSFrançois Tigeot value_count = property->num_values; 28455718399fSFrançois Tigeot 28465718399fSFrançois Tigeot strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 28475718399fSFrançois Tigeot out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 28485718399fSFrançois Tigeot out_resp->flags = property->flags; 28495718399fSFrançois Tigeot 28505718399fSFrançois Tigeot if ((out_resp->count_values >= value_count) && value_count) { 28515718399fSFrançois Tigeot values_ptr = (uint64_t *)(uintptr_t)out_resp->values_ptr; 28525718399fSFrançois Tigeot for (i = 0; i < value_count; i++) { 28535718399fSFrançois Tigeot if (copyout(&property->values[i], values_ptr + i, sizeof(uint64_t))) { 28545718399fSFrançois Tigeot ret = -EFAULT; 28555718399fSFrançois Tigeot goto done; 28565718399fSFrançois Tigeot } 28575718399fSFrançois Tigeot } 28585718399fSFrançois Tigeot } 28595718399fSFrançois Tigeot out_resp->count_values = value_count; 28605718399fSFrançois Tigeot 28615718399fSFrançois Tigeot if (property->flags & DRM_MODE_PROP_ENUM) { 28625718399fSFrançois Tigeot if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 28635718399fSFrançois Tigeot copied = 0; 28645718399fSFrançois Tigeot enum_ptr = (struct drm_mode_property_enum *)(uintptr_t)out_resp->enum_blob_ptr; 28655718399fSFrançois Tigeot list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 28665718399fSFrançois Tigeot 28675718399fSFrançois Tigeot if (copyout(&prop_enum->value, &enum_ptr[copied].value, sizeof(uint64_t))) { 28685718399fSFrançois Tigeot ret = -EFAULT; 28695718399fSFrançois Tigeot goto done; 28705718399fSFrançois Tigeot } 28715718399fSFrançois Tigeot 28725718399fSFrançois Tigeot if (copyout(&prop_enum->name, 28735718399fSFrançois Tigeot &enum_ptr[copied].name,DRM_PROP_NAME_LEN)) { 28745718399fSFrançois Tigeot ret = -EFAULT; 28755718399fSFrançois Tigeot goto done; 28765718399fSFrançois Tigeot } 28775718399fSFrançois Tigeot copied++; 28785718399fSFrançois Tigeot } 28795718399fSFrançois Tigeot } 28805718399fSFrançois Tigeot out_resp->count_enum_blobs = enum_count; 28815718399fSFrançois Tigeot } 28825718399fSFrançois Tigeot 28835718399fSFrançois Tigeot if (property->flags & DRM_MODE_PROP_BLOB) { 28845718399fSFrançois Tigeot if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { 28855718399fSFrançois Tigeot copied = 0; 28865718399fSFrançois Tigeot blob_id_ptr = (uint32_t *)(uintptr_t)out_resp->enum_blob_ptr; 28875718399fSFrançois Tigeot blob_length_ptr = (uint32_t *)(uintptr_t)out_resp->values_ptr; 28885718399fSFrançois Tigeot 28895718399fSFrançois Tigeot list_for_each_entry(prop_blob, &property->enum_blob_list, head) { 28905718399fSFrançois Tigeot if (copyout(&prop_blob->base.id, 28915718399fSFrançois Tigeot blob_id_ptr + copied, sizeof(uint32_t))) { 28925718399fSFrançois Tigeot ret = -EFAULT; 28935718399fSFrançois Tigeot goto done; 28945718399fSFrançois Tigeot } 28955718399fSFrançois Tigeot 28965718399fSFrançois Tigeot if (copyout(&prop_blob->length, 28975718399fSFrançois Tigeot blob_length_ptr + copied, sizeof(uint32_t))) { 28985718399fSFrançois Tigeot ret = -EFAULT; 28995718399fSFrançois Tigeot goto done; 29005718399fSFrançois Tigeot } 29015718399fSFrançois Tigeot 29025718399fSFrançois Tigeot copied++; 29035718399fSFrançois Tigeot } 29045718399fSFrançois Tigeot } 29055718399fSFrançois Tigeot out_resp->count_enum_blobs = blob_count; 29065718399fSFrançois Tigeot } 29075718399fSFrançois Tigeot done: 29085718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 29095718399fSFrançois Tigeot return ret; 29105718399fSFrançois Tigeot } 29115718399fSFrançois Tigeot 29125718399fSFrançois Tigeot static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, 29135718399fSFrançois Tigeot void *data) 29145718399fSFrançois Tigeot { 29155718399fSFrançois Tigeot struct drm_property_blob *blob; 29165718399fSFrançois Tigeot int ret; 29175718399fSFrançois Tigeot 29185718399fSFrançois Tigeot if (!length || !data) 29195718399fSFrançois Tigeot return NULL; 29205718399fSFrançois Tigeot 29215718399fSFrançois Tigeot blob = kmalloc(sizeof(struct drm_property_blob) + length, DRM_MEM_KMS, 29225718399fSFrançois Tigeot M_WAITOK | M_ZERO); 29235718399fSFrançois Tigeot 29245718399fSFrançois Tigeot ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 29255718399fSFrançois Tigeot if (ret) { 29265718399fSFrançois Tigeot drm_free(blob, DRM_MEM_KMS); 29275718399fSFrançois Tigeot return (NULL); 29285718399fSFrançois Tigeot } 29295718399fSFrançois Tigeot 29305718399fSFrançois Tigeot blob->length = length; 29315718399fSFrançois Tigeot 29325718399fSFrançois Tigeot memcpy(blob->data, data, length); 29335718399fSFrançois Tigeot 29345718399fSFrançois Tigeot list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 29355718399fSFrançois Tigeot return blob; 29365718399fSFrançois Tigeot } 29375718399fSFrançois Tigeot 29385718399fSFrançois Tigeot static void drm_property_destroy_blob(struct drm_device *dev, 29395718399fSFrançois Tigeot struct drm_property_blob *blob) 29405718399fSFrançois Tigeot { 29415718399fSFrançois Tigeot drm_mode_object_put(dev, &blob->base); 29425718399fSFrançois Tigeot list_del(&blob->head); 29435718399fSFrançois Tigeot drm_free(blob, DRM_MEM_KMS); 29445718399fSFrançois Tigeot } 29455718399fSFrançois Tigeot 29465718399fSFrançois Tigeot int drm_mode_getblob_ioctl(struct drm_device *dev, 29475718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 29485718399fSFrançois Tigeot { 29495718399fSFrançois Tigeot struct drm_mode_object *obj; 29505718399fSFrançois Tigeot struct drm_mode_get_blob *out_resp = data; 29515718399fSFrançois Tigeot struct drm_property_blob *blob; 29525718399fSFrançois Tigeot int ret = 0; 29535718399fSFrançois Tigeot void *blob_ptr; 29545718399fSFrançois Tigeot 29555718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 29565718399fSFrançois Tigeot return -EINVAL; 29575718399fSFrançois Tigeot 29585718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 29595718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); 29605718399fSFrançois Tigeot if (!obj) { 29615718399fSFrançois Tigeot ret = -EINVAL; 29625718399fSFrançois Tigeot goto done; 29635718399fSFrançois Tigeot } 29645718399fSFrançois Tigeot blob = obj_to_blob(obj); 29655718399fSFrançois Tigeot 29665718399fSFrançois Tigeot if (out_resp->length == blob->length) { 29675718399fSFrançois Tigeot blob_ptr = (void *)(unsigned long)out_resp->data; 29685718399fSFrançois Tigeot if (copyout(blob->data, blob_ptr, blob->length)){ 29695718399fSFrançois Tigeot ret = -EFAULT; 29705718399fSFrançois Tigeot goto done; 29715718399fSFrançois Tigeot } 29725718399fSFrançois Tigeot } 29735718399fSFrançois Tigeot out_resp->length = blob->length; 29745718399fSFrançois Tigeot 29755718399fSFrançois Tigeot done: 29765718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 29775718399fSFrançois Tigeot return ret; 29785718399fSFrançois Tigeot } 29795718399fSFrançois Tigeot 29805718399fSFrançois Tigeot int drm_mode_connector_update_edid_property(struct drm_connector *connector, 29815718399fSFrançois Tigeot struct edid *edid) 29825718399fSFrançois Tigeot { 29835718399fSFrançois Tigeot struct drm_device *dev = connector->dev; 29845718399fSFrançois Tigeot int ret = 0, size; 29855718399fSFrançois Tigeot 29865718399fSFrançois Tigeot if (connector->edid_blob_ptr) 29875718399fSFrançois Tigeot drm_property_destroy_blob(dev, connector->edid_blob_ptr); 29885718399fSFrançois Tigeot 29895718399fSFrançois Tigeot /* Delete edid, when there is none. */ 29905718399fSFrançois Tigeot if (!edid) { 29915718399fSFrançois Tigeot connector->edid_blob_ptr = NULL; 29925718399fSFrançois Tigeot ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); 29935718399fSFrançois Tigeot return ret; 29945718399fSFrançois Tigeot } 29955718399fSFrançois Tigeot 29965718399fSFrançois Tigeot size = EDID_LENGTH * (1 + edid->extensions); 29975718399fSFrançois Tigeot connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 29985718399fSFrançois Tigeot size, edid); 29995718399fSFrançois Tigeot 30005718399fSFrançois Tigeot ret = drm_connector_property_set_value(connector, 30015718399fSFrançois Tigeot dev->mode_config.edid_property, 30025718399fSFrançois Tigeot connector->edid_blob_ptr->base.id); 30035718399fSFrançois Tigeot 30045718399fSFrançois Tigeot return ret; 30055718399fSFrançois Tigeot } 30065718399fSFrançois Tigeot 30075718399fSFrançois Tigeot int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 30085718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 30095718399fSFrançois Tigeot { 30105718399fSFrançois Tigeot struct drm_mode_connector_set_property *out_resp = data; 30115718399fSFrançois Tigeot struct drm_mode_object *obj; 30125718399fSFrançois Tigeot struct drm_property *property; 30135718399fSFrançois Tigeot struct drm_connector *connector; 30145718399fSFrançois Tigeot int ret = -EINVAL; 30155718399fSFrançois Tigeot int i; 30165718399fSFrançois Tigeot 30175718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 30185718399fSFrançois Tigeot return -EINVAL; 30195718399fSFrançois Tigeot 30205718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 30215718399fSFrançois Tigeot 30225718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); 30235718399fSFrançois Tigeot if (!obj) { 30245718399fSFrançois Tigeot goto out; 30255718399fSFrançois Tigeot } 30265718399fSFrançois Tigeot connector = obj_to_connector(obj); 30275718399fSFrançois Tigeot 30285718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 30295718399fSFrançois Tigeot if (connector->property_ids[i] == out_resp->prop_id) 30305718399fSFrançois Tigeot break; 30315718399fSFrançois Tigeot } 30325718399fSFrançois Tigeot 30335718399fSFrançois Tigeot if (i == DRM_CONNECTOR_MAX_PROPERTY) { 30345718399fSFrançois Tigeot goto out; 30355718399fSFrançois Tigeot } 30365718399fSFrançois Tigeot 30375718399fSFrançois Tigeot obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); 30385718399fSFrançois Tigeot if (!obj) { 30395718399fSFrançois Tigeot goto out; 30405718399fSFrançois Tigeot } 30415718399fSFrançois Tigeot property = obj_to_property(obj); 30425718399fSFrançois Tigeot 30435718399fSFrançois Tigeot if (property->flags & DRM_MODE_PROP_IMMUTABLE) 30445718399fSFrançois Tigeot goto out; 30455718399fSFrançois Tigeot 30465718399fSFrançois Tigeot if (property->flags & DRM_MODE_PROP_RANGE) { 30475718399fSFrançois Tigeot if (out_resp->value < property->values[0]) 30485718399fSFrançois Tigeot goto out; 30495718399fSFrançois Tigeot 30505718399fSFrançois Tigeot if (out_resp->value > property->values[1]) 30515718399fSFrançois Tigeot goto out; 30525718399fSFrançois Tigeot } else { 30535718399fSFrançois Tigeot int found = 0; 30545718399fSFrançois Tigeot for (i = 0; i < property->num_values; i++) { 30555718399fSFrançois Tigeot if (property->values[i] == out_resp->value) { 30565718399fSFrançois Tigeot found = 1; 30575718399fSFrançois Tigeot break; 30585718399fSFrançois Tigeot } 30595718399fSFrançois Tigeot } 30605718399fSFrançois Tigeot if (!found) { 30615718399fSFrançois Tigeot goto out; 30625718399fSFrançois Tigeot } 30635718399fSFrançois Tigeot } 30645718399fSFrançois Tigeot 30655718399fSFrançois Tigeot /* Do DPMS ourselves */ 30665718399fSFrançois Tigeot if (property == connector->dev->mode_config.dpms_property) { 30675718399fSFrançois Tigeot if (connector->funcs->dpms) 30685718399fSFrançois Tigeot (*connector->funcs->dpms)(connector, (int) out_resp->value); 30695718399fSFrançois Tigeot ret = 0; 30705718399fSFrançois Tigeot } else if (connector->funcs->set_property) 30715718399fSFrançois Tigeot ret = connector->funcs->set_property(connector, property, out_resp->value); 30725718399fSFrançois Tigeot 30735718399fSFrançois Tigeot /* store the property value if successful */ 30745718399fSFrançois Tigeot if (!ret) 30755718399fSFrançois Tigeot drm_connector_property_set_value(connector, property, out_resp->value); 30765718399fSFrançois Tigeot out: 30775718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 30785718399fSFrançois Tigeot return ret; 30795718399fSFrançois Tigeot } 30805718399fSFrançois Tigeot 30815718399fSFrançois Tigeot int drm_mode_connector_attach_encoder(struct drm_connector *connector, 30825718399fSFrançois Tigeot struct drm_encoder *encoder) 30835718399fSFrançois Tigeot { 30845718399fSFrançois Tigeot int i; 30855718399fSFrançois Tigeot 30865718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 30875718399fSFrançois Tigeot if (connector->encoder_ids[i] == 0) { 30885718399fSFrançois Tigeot connector->encoder_ids[i] = encoder->base.id; 30895718399fSFrançois Tigeot return 0; 30905718399fSFrançois Tigeot } 30915718399fSFrançois Tigeot } 30925718399fSFrançois Tigeot return -ENOMEM; 30935718399fSFrançois Tigeot } 30945718399fSFrançois Tigeot 30955718399fSFrançois Tigeot void drm_mode_connector_detach_encoder(struct drm_connector *connector, 30965718399fSFrançois Tigeot struct drm_encoder *encoder) 30975718399fSFrançois Tigeot { 30985718399fSFrançois Tigeot int i; 30995718399fSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 31005718399fSFrançois Tigeot if (connector->encoder_ids[i] == encoder->base.id) { 31015718399fSFrançois Tigeot connector->encoder_ids[i] = 0; 31025718399fSFrançois Tigeot if (connector->encoder == encoder) 31035718399fSFrançois Tigeot connector->encoder = NULL; 31045718399fSFrançois Tigeot break; 31055718399fSFrançois Tigeot } 31065718399fSFrançois Tigeot } 31075718399fSFrançois Tigeot } 31085718399fSFrançois Tigeot 31095718399fSFrançois Tigeot int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 31105718399fSFrançois Tigeot int gamma_size) 31115718399fSFrançois Tigeot { 31125718399fSFrançois Tigeot crtc->gamma_size = gamma_size; 31135718399fSFrançois Tigeot 31145718399fSFrançois Tigeot crtc->gamma_store = kmalloc(gamma_size * sizeof(uint16_t) * 3, 31155718399fSFrançois Tigeot DRM_MEM_KMS, M_WAITOK | M_ZERO); 31165718399fSFrançois Tigeot 31175718399fSFrançois Tigeot return 0; 31185718399fSFrançois Tigeot } 31195718399fSFrançois Tigeot 31205718399fSFrançois Tigeot int drm_mode_gamma_set_ioctl(struct drm_device *dev, 31215718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 31225718399fSFrançois Tigeot { 31235718399fSFrançois Tigeot struct drm_mode_crtc_lut *crtc_lut = data; 31245718399fSFrançois Tigeot struct drm_mode_object *obj; 31255718399fSFrançois Tigeot struct drm_crtc *crtc; 31265718399fSFrançois Tigeot void *r_base, *g_base, *b_base; 31275718399fSFrançois Tigeot int size; 31285718399fSFrançois Tigeot int ret = 0; 31295718399fSFrançois Tigeot 31305718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 31315718399fSFrançois Tigeot return -EINVAL; 31325718399fSFrançois Tigeot 31335718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 31345718399fSFrançois Tigeot obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 31355718399fSFrançois Tigeot if (!obj) { 31365718399fSFrançois Tigeot ret = -EINVAL; 31375718399fSFrançois Tigeot goto out; 31385718399fSFrançois Tigeot } 31395718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 31405718399fSFrançois Tigeot 31415718399fSFrançois Tigeot /* memcpy into gamma store */ 31425718399fSFrançois Tigeot if (crtc_lut->gamma_size != crtc->gamma_size) { 31435718399fSFrançois Tigeot ret = -EINVAL; 31445718399fSFrançois Tigeot goto out; 31455718399fSFrançois Tigeot } 31465718399fSFrançois Tigeot 31475718399fSFrançois Tigeot size = crtc_lut->gamma_size * (sizeof(uint16_t)); 31485718399fSFrançois Tigeot r_base = crtc->gamma_store; 31495718399fSFrançois Tigeot if (copyin((void *)(uintptr_t)crtc_lut->red, r_base, size)) { 31505718399fSFrançois Tigeot ret = -EFAULT; 31515718399fSFrançois Tigeot goto out; 31525718399fSFrançois Tigeot } 31535718399fSFrançois Tigeot 31545718399fSFrançois Tigeot g_base = (char *)r_base + size; 31555718399fSFrançois Tigeot if (copyin((void *)(uintptr_t)crtc_lut->green, g_base, size)) { 31565718399fSFrançois Tigeot ret = -EFAULT; 31575718399fSFrançois Tigeot goto out; 31585718399fSFrançois Tigeot } 31595718399fSFrançois Tigeot 31605718399fSFrançois Tigeot b_base = (char *)g_base + size; 31615718399fSFrançois Tigeot if (copyin((void *)(uintptr_t)crtc_lut->blue, b_base, size)) { 31625718399fSFrançois Tigeot ret = -EFAULT; 31635718399fSFrançois Tigeot goto out; 31645718399fSFrançois Tigeot } 31655718399fSFrançois Tigeot 31665718399fSFrançois Tigeot crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 31675718399fSFrançois Tigeot 31685718399fSFrançois Tigeot out: 31695718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 31705718399fSFrançois Tigeot return ret; 31715718399fSFrançois Tigeot 31725718399fSFrançois Tigeot } 31735718399fSFrançois Tigeot 31745718399fSFrançois Tigeot int drm_mode_gamma_get_ioctl(struct drm_device *dev, 31755718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 31765718399fSFrançois Tigeot { 31775718399fSFrançois Tigeot struct drm_mode_crtc_lut *crtc_lut = data; 31785718399fSFrançois Tigeot struct drm_mode_object *obj; 31795718399fSFrançois Tigeot struct drm_crtc *crtc; 31805718399fSFrançois Tigeot void *r_base, *g_base, *b_base; 31815718399fSFrançois Tigeot int size; 31825718399fSFrançois Tigeot int ret = 0; 31835718399fSFrançois Tigeot 31845718399fSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 31855718399fSFrançois Tigeot return -EINVAL; 31865718399fSFrançois Tigeot 31875718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 31885718399fSFrançois Tigeot obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 31895718399fSFrançois Tigeot if (!obj) { 31905718399fSFrançois Tigeot ret = -EINVAL; 31915718399fSFrançois Tigeot goto out; 31925718399fSFrançois Tigeot } 31935718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 31945718399fSFrançois Tigeot 31955718399fSFrançois Tigeot /* memcpy into gamma store */ 31965718399fSFrançois Tigeot if (crtc_lut->gamma_size != crtc->gamma_size) { 31975718399fSFrançois Tigeot ret = -EINVAL; 31985718399fSFrançois Tigeot goto out; 31995718399fSFrançois Tigeot } 32005718399fSFrançois Tigeot 32015718399fSFrançois Tigeot size = crtc_lut->gamma_size * (sizeof(uint16_t)); 32025718399fSFrançois Tigeot r_base = crtc->gamma_store; 32035718399fSFrançois Tigeot if (copyout(r_base, (void *)(uintptr_t)crtc_lut->red, size)) { 32045718399fSFrançois Tigeot ret = -EFAULT; 32055718399fSFrançois Tigeot goto out; 32065718399fSFrançois Tigeot } 32075718399fSFrançois Tigeot 32085718399fSFrançois Tigeot g_base = (char *)r_base + size; 32095718399fSFrançois Tigeot if (copyout(g_base, (void *)(uintptr_t)crtc_lut->green, size)) { 32105718399fSFrançois Tigeot ret = -EFAULT; 32115718399fSFrançois Tigeot goto out; 32125718399fSFrançois Tigeot } 32135718399fSFrançois Tigeot 32145718399fSFrançois Tigeot b_base = (char *)g_base + size; 32155718399fSFrançois Tigeot if (copyout(b_base, (void *)(uintptr_t)crtc_lut->blue, size)) { 32165718399fSFrançois Tigeot ret = -EFAULT; 32175718399fSFrançois Tigeot goto out; 32185718399fSFrançois Tigeot } 32195718399fSFrançois Tigeot out: 32205718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 32215718399fSFrançois Tigeot return ret; 32225718399fSFrançois Tigeot } 32235718399fSFrançois Tigeot 32245718399fSFrançois Tigeot static void 32255718399fSFrançois Tigeot drm_kms_free(void *arg) 32265718399fSFrançois Tigeot { 32275718399fSFrançois Tigeot 32285718399fSFrançois Tigeot drm_free(arg, DRM_MEM_KMS); 32295718399fSFrançois Tigeot } 32305718399fSFrançois Tigeot 32315718399fSFrançois Tigeot int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, 32325718399fSFrançois Tigeot struct drm_file *file_priv) 32335718399fSFrançois Tigeot { 32345718399fSFrançois Tigeot struct drm_mode_crtc_page_flip *page_flip = data; 32355718399fSFrançois Tigeot struct drm_mode_object *obj; 32365718399fSFrançois Tigeot struct drm_crtc *crtc; 32375718399fSFrançois Tigeot struct drm_framebuffer *fb; 32385718399fSFrançois Tigeot struct drm_pending_vblank_event *e = NULL; 32395718399fSFrançois Tigeot int ret = EINVAL; 32405718399fSFrançois Tigeot 32415718399fSFrançois Tigeot if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 32425718399fSFrançois Tigeot page_flip->reserved != 0) 32435718399fSFrançois Tigeot return (EINVAL); 32445718399fSFrançois Tigeot 32455718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_EXCLUSIVE); 32465718399fSFrançois Tigeot obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); 32475718399fSFrançois Tigeot if (!obj) 32485718399fSFrançois Tigeot goto out; 32495718399fSFrançois Tigeot crtc = obj_to_crtc(obj); 32505718399fSFrançois Tigeot 32515718399fSFrançois Tigeot if (crtc->fb == NULL) { 32525718399fSFrançois Tigeot /* The framebuffer is currently unbound, presumably 32535718399fSFrançois Tigeot * due to a hotplug event, that userspace has not 32545718399fSFrançois Tigeot * yet discovered. 32555718399fSFrançois Tigeot */ 32565718399fSFrançois Tigeot ret = EBUSY; 32575718399fSFrançois Tigeot goto out; 32585718399fSFrançois Tigeot } 32595718399fSFrançois Tigeot 32605718399fSFrançois Tigeot if (crtc->funcs->page_flip == NULL) 32615718399fSFrançois Tigeot goto out; 32625718399fSFrançois Tigeot 32635718399fSFrançois Tigeot obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); 32645718399fSFrançois Tigeot if (!obj) 32655718399fSFrançois Tigeot goto out; 32665718399fSFrançois Tigeot fb = obj_to_fb(obj); 32675718399fSFrançois Tigeot 32685718399fSFrançois Tigeot if (crtc->mode.hdisplay > fb->width || 32695718399fSFrançois Tigeot crtc->mode.vdisplay > fb->height || 32705718399fSFrançois Tigeot crtc->x > fb->width - crtc->mode.hdisplay || 32715718399fSFrançois Tigeot crtc->y > fb->height - crtc->mode.vdisplay) { 32725718399fSFrançois Tigeot DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n", 32735718399fSFrançois Tigeot fb->width, fb->height, 32745718399fSFrançois Tigeot crtc->mode.hdisplay, crtc->mode.vdisplay, 32755718399fSFrançois Tigeot crtc->x, crtc->y); 32765718399fSFrançois Tigeot ret = ENOSPC; 32775718399fSFrançois Tigeot goto out; 32785718399fSFrançois Tigeot } 32795718399fSFrançois Tigeot 32805718399fSFrançois Tigeot if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 32815718399fSFrançois Tigeot ret = ENOMEM; 32825718399fSFrançois Tigeot lockmgr(&dev->event_lock, LK_EXCLUSIVE); 32835718399fSFrançois Tigeot if (file_priv->event_space < sizeof e->event) { 32845718399fSFrançois Tigeot lockmgr(&dev->event_lock, LK_RELEASE); 32855718399fSFrançois Tigeot goto out; 32865718399fSFrançois Tigeot } 32875718399fSFrançois Tigeot file_priv->event_space -= sizeof e->event; 32885718399fSFrançois Tigeot lockmgr(&dev->event_lock, LK_RELEASE); 32895718399fSFrançois Tigeot 32905718399fSFrançois Tigeot e = kmalloc(sizeof *e, DRM_MEM_KMS, M_WAITOK | M_ZERO); 32915718399fSFrançois Tigeot 32925718399fSFrançois Tigeot e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 32935718399fSFrançois Tigeot e->event.base.length = sizeof e->event; 32945718399fSFrançois Tigeot e->event.user_data = page_flip->user_data; 32955718399fSFrançois Tigeot e->base.event = &e->event.base; 32965718399fSFrançois Tigeot e->base.file_priv = file_priv; 32975718399fSFrançois Tigeot e->base.destroy = 32985718399fSFrançois Tigeot (void (*) (struct drm_pending_event *))drm_kms_free; 32995718399fSFrançois Tigeot } 33005718399fSFrançois Tigeot 33015718399fSFrançois Tigeot ret = -crtc->funcs->page_flip(crtc, fb, e); 33025718399fSFrançois Tigeot if (ret != 0) { 33035718399fSFrançois Tigeot if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 33045718399fSFrançois Tigeot lockmgr(&dev->event_lock, LK_EXCLUSIVE); 33055718399fSFrançois Tigeot file_priv->event_space += sizeof e->event; 33065718399fSFrançois Tigeot lockmgr(&dev->event_lock, LK_RELEASE); 33075718399fSFrançois Tigeot drm_free(e, DRM_MEM_KMS); 33085718399fSFrançois Tigeot } 33095718399fSFrançois Tigeot } 33105718399fSFrançois Tigeot 33115718399fSFrançois Tigeot out: 33125718399fSFrançois Tigeot lockmgr(&dev->mode_config.lock, LK_RELEASE); 33135718399fSFrançois Tigeot return (ret); 33145718399fSFrançois Tigeot } 33155718399fSFrançois Tigeot 33165718399fSFrançois Tigeot void drm_mode_config_reset(struct drm_device *dev) 33175718399fSFrançois Tigeot { 33185718399fSFrançois Tigeot struct drm_crtc *crtc; 33195718399fSFrançois Tigeot struct drm_encoder *encoder; 33205718399fSFrançois Tigeot struct drm_connector *connector; 33215718399fSFrançois Tigeot 33225718399fSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 33235718399fSFrançois Tigeot if (crtc->funcs->reset) 33245718399fSFrançois Tigeot crtc->funcs->reset(crtc); 33255718399fSFrançois Tigeot 33265718399fSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 33275718399fSFrançois Tigeot if (encoder->funcs->reset) 33285718399fSFrançois Tigeot encoder->funcs->reset(encoder); 33295718399fSFrançois Tigeot 33305718399fSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) 33315718399fSFrançois Tigeot if (connector->funcs->reset) 33325718399fSFrançois Tigeot connector->funcs->reset(connector); 33335718399fSFrançois Tigeot } 33345718399fSFrançois Tigeot 33355718399fSFrançois Tigeot int drm_mode_create_dumb_ioctl(struct drm_device *dev, 33365718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 33375718399fSFrançois Tigeot { 33385718399fSFrançois Tigeot struct drm_mode_create_dumb *args = data; 33395718399fSFrançois Tigeot 33405718399fSFrançois Tigeot if (!dev->driver->dumb_create) 33415718399fSFrançois Tigeot return -ENOTSUP; 33425718399fSFrançois Tigeot return dev->driver->dumb_create(file_priv, dev, args); 33435718399fSFrançois Tigeot } 33445718399fSFrançois Tigeot 33455718399fSFrançois Tigeot int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 33465718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 33475718399fSFrançois Tigeot { 33485718399fSFrançois Tigeot struct drm_mode_map_dumb *args = data; 33495718399fSFrançois Tigeot 33505718399fSFrançois Tigeot /* call driver ioctl to get mmap offset */ 33515718399fSFrançois Tigeot if (!dev->driver->dumb_map_offset) 33525718399fSFrançois Tigeot return -ENOTSUP; 33535718399fSFrançois Tigeot 33545718399fSFrançois Tigeot return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 33555718399fSFrançois Tigeot } 33565718399fSFrançois Tigeot 33575718399fSFrançois Tigeot int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 33585718399fSFrançois Tigeot void *data, struct drm_file *file_priv) 33595718399fSFrançois Tigeot { 33605718399fSFrançois Tigeot struct drm_mode_destroy_dumb *args = data; 33615718399fSFrançois Tigeot 33625718399fSFrançois Tigeot if (!dev->driver->dumb_destroy) 33635718399fSFrançois Tigeot return -ENOTSUP; 33645718399fSFrançois Tigeot 33655718399fSFrançois Tigeot return dev->driver->dumb_destroy(file_priv, dev, args->handle); 33665718399fSFrançois Tigeot } 33675718399fSFrançois Tigeot 33685718399fSFrançois Tigeot /* 33695718399fSFrançois Tigeot * Just need to support RGB formats here for compat with code that doesn't 33705718399fSFrançois Tigeot * use pixel formats directly yet. 33715718399fSFrançois Tigeot */ 33725718399fSFrançois Tigeot void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 33735718399fSFrançois Tigeot int *bpp) 33745718399fSFrançois Tigeot { 33755718399fSFrançois Tigeot switch (format) { 33765718399fSFrançois Tigeot case DRM_FORMAT_RGB332: 33775718399fSFrançois Tigeot case DRM_FORMAT_BGR233: 33785718399fSFrançois Tigeot *depth = 8; 33795718399fSFrançois Tigeot *bpp = 8; 33805718399fSFrançois Tigeot break; 33815718399fSFrançois Tigeot case DRM_FORMAT_XRGB1555: 33825718399fSFrançois Tigeot case DRM_FORMAT_XBGR1555: 33835718399fSFrançois Tigeot case DRM_FORMAT_RGBX5551: 33845718399fSFrançois Tigeot case DRM_FORMAT_BGRX5551: 33855718399fSFrançois Tigeot case DRM_FORMAT_ARGB1555: 33865718399fSFrançois Tigeot case DRM_FORMAT_ABGR1555: 33875718399fSFrançois Tigeot case DRM_FORMAT_RGBA5551: 33885718399fSFrançois Tigeot case DRM_FORMAT_BGRA5551: 33895718399fSFrançois Tigeot *depth = 15; 33905718399fSFrançois Tigeot *bpp = 16; 33915718399fSFrançois Tigeot break; 33925718399fSFrançois Tigeot case DRM_FORMAT_RGB565: 33935718399fSFrançois Tigeot case DRM_FORMAT_BGR565: 33945718399fSFrançois Tigeot *depth = 16; 33955718399fSFrançois Tigeot *bpp = 16; 33965718399fSFrançois Tigeot break; 33975718399fSFrançois Tigeot case DRM_FORMAT_RGB888: 33985718399fSFrançois Tigeot case DRM_FORMAT_BGR888: 33995718399fSFrançois Tigeot *depth = 24; 34005718399fSFrançois Tigeot *bpp = 24; 34015718399fSFrançois Tigeot break; 34025718399fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 34035718399fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 34045718399fSFrançois Tigeot case DRM_FORMAT_RGBX8888: 34055718399fSFrançois Tigeot case DRM_FORMAT_BGRX8888: 34065718399fSFrançois Tigeot *depth = 24; 34075718399fSFrançois Tigeot *bpp = 32; 34085718399fSFrançois Tigeot break; 34095718399fSFrançois Tigeot case DRM_FORMAT_XRGB2101010: 34105718399fSFrançois Tigeot case DRM_FORMAT_XBGR2101010: 34115718399fSFrançois Tigeot case DRM_FORMAT_RGBX1010102: 34125718399fSFrançois Tigeot case DRM_FORMAT_BGRX1010102: 34135718399fSFrançois Tigeot case DRM_FORMAT_ARGB2101010: 34145718399fSFrançois Tigeot case DRM_FORMAT_ABGR2101010: 34155718399fSFrançois Tigeot case DRM_FORMAT_RGBA1010102: 34165718399fSFrançois Tigeot case DRM_FORMAT_BGRA1010102: 34175718399fSFrançois Tigeot *depth = 30; 34185718399fSFrançois Tigeot *bpp = 32; 34195718399fSFrançois Tigeot break; 34205718399fSFrançois Tigeot case DRM_FORMAT_ARGB8888: 34215718399fSFrançois Tigeot case DRM_FORMAT_ABGR8888: 34225718399fSFrançois Tigeot case DRM_FORMAT_RGBA8888: 34235718399fSFrançois Tigeot case DRM_FORMAT_BGRA8888: 34245718399fSFrançois Tigeot *depth = 32; 34255718399fSFrançois Tigeot *bpp = 32; 34265718399fSFrançois Tigeot break; 34275718399fSFrançois Tigeot default: 34285718399fSFrançois Tigeot DRM_DEBUG_KMS("unsupported pixel format\n"); 34295718399fSFrançois Tigeot *depth = 0; 34305718399fSFrançois Tigeot *bpp = 0; 34315718399fSFrançois Tigeot break; 34325718399fSFrançois Tigeot } 34335718399fSFrançois Tigeot } 3434