drm_crtc.c revision 235783
112675Sjulian/* 24Srgrimes * Copyright (c) 2006-2008 Intel Corporation 34Srgrimes * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 44Srgrimes * Copyright (c) 2008 Red Hat Inc. 54Srgrimes * 64Srgrimes * DRM core CRTC related functions 74Srgrimes * 841693Simp * Permission to use, copy, modify, distribute, and sell this software and its 941693Simp * documentation for any purpose is hereby granted without fee, provided that 1041693Simp * the above copyright notice appear in all copies and that both that copyright 1141693Simp * notice and this permission notice appear in supporting documentation, and 125512Sjoerg * that the name of the copyright holders not be used in advertising or 132838Sdg * publicity pertaining to distribution of the software without specific, 142838Sdg * written prior permission. The copyright holders make no representations 152838Sdg * about the suitability of this software for any purpose. It is provided "as 165512Sjoerg * is" without express or implied warranty. 175512Sjoerg * 182838Sdg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 195417Sjoerg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 202838Sdg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 214Srgrimes * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 224Srgrimes * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 234Srgrimes * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 244Srgrimes * OF THIS SOFTWARE. 254Srgrimes * 264Srgrimes * Authors: 274Srgrimes * Keith Packard 284Srgrimes * Eric Anholt <eric@anholt.net> 294Srgrimes * Dave Airlie <airlied@linux.ie> 304Srgrimes * Jesse Barnes <jesse.barnes@intel.com> 314Srgrimes */ 324Srgrimes#include <sys/cdefs.h> 334Srgrimes__FBSDID("$FreeBSD: head/sys/dev/drm2/drm_crtc.c 235783 2012-05-22 11:07:44Z kib $"); 344Srgrimes 354Srgrimes#include <dev/drm2/drm.h> 364Srgrimes#include <dev/drm2/drmP.h> 374Srgrimes#include <dev/drm2/drm_crtc.h> 384Srgrimes#include <dev/drm2/drm_edid.h> 394Srgrimes#include <dev/drm2/drm_fourcc.h> 404Srgrimes#include <sys/limits.h> 414Srgrimes 424Srgrimes/* Avoid boilerplate. I'm tired of typing. */ 434Srgrimes#define DRM_ENUM_NAME_FN(fnname, list) \ 444Srgrimes char *fnname(int val) \ 454Srgrimes { \ 464Srgrimes int i; \ 474Srgrimes for (i = 0; i < DRM_ARRAY_SIZE(list); i++) { \ 484Srgrimes if (list[i].type == val) \ 49471Srgrimes return list[i].name; \ 5041693Simp } \ 514Srgrimes return "(unknown)"; \ 524Srgrimes } 534Srgrimes 541110Salm/* 551110Salm * Global properties 561110Salm */ 571110Salmstatic struct drm_prop_enum_list drm_dpms_enum_list[] = 584Srgrimes{ { DRM_MODE_DPMS_ON, "On" }, 5932726Seivind { DRM_MODE_DPMS_STANDBY, "Standby" }, 6029494Sjoerg { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 614Srgrimes { DRM_MODE_DPMS_OFF, "Off" } 621110Salm}; 631110Salm 641110SalmDRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 651110Salm 661110Salm/* 671110Salm * Optional properties 6824131Sbde */ 696724Sbdestatic struct drm_prop_enum_list drm_scaling_mode_enum_list[] = 701110Salm{ 711110Salm { DRM_MODE_SCALE_NONE, "None" }, 721110Salm { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 7339228Sgibbs { DRM_MODE_SCALE_CENTER, "Center" }, 741110Salm { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 752838Sdg}; 761110Salm 772056Swollmanstatic struct drm_prop_enum_list drm_dithering_mode_enum_list[] = 782056Swollman{ 792056Swollman { DRM_MODE_DITHERING_OFF, "Off" }, 802056Swollman { DRM_MODE_DITHERING_ON, "On" }, 812056Swollman { DRM_MODE_DITHERING_AUTO, "Automatic" }, 825417Sjoerg}; 833085Sphk 843085Sphk/* 853085Sphk * Non-global properties, but "required" for certain connectors. 863085Sphk */ 8735319Sjulianstatic struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = 8810537Sjulian{ 8935319Sjulian { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 904Srgrimes { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 91878Sache { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 92878Sache}; 934Srgrimes 9430574SjoergDRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 9530574Sjoerg 9641693Simpstatic struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = 9741693Simp{ 9841693Simp { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 9941693Simp { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 10030574Sjoerg { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 10130574Sjoerg}; 10230574Sjoerg 10330574SjoergDRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 1042838Sdg drm_dvi_i_subconnector_enum_list) 1052838Sdg 1062838Sdgstatic struct drm_prop_enum_list drm_tv_select_enum_list[] = 1072838Sdg{ 1082838Sdg { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 1092838Sdg { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 1105417Sjoerg { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 1115417Sjoerg { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 1125417Sjoerg { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 1135417Sjoerg}; 1145417Sjoerg 115878SacheDRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 116878Sache 117863Sachestatic struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = 1182838Sdg{ 1191110Salm { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 1201110Salm { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 1211110Salm { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 1221110Salm { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 1231110Salm { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 1241110Salm}; 1251110Salm 1261110SalmDRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 1271110Salm drm_tv_subconnector_enum_list) 1281110Salm 129863Sachestatic struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 1301110Salm { DRM_MODE_DIRTY_OFF, "Off" }, 1311110Salm { DRM_MODE_DIRTY_ON, "On" }, 1321110Salm { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 1331110Salm}; 1341110Salm 1351110SalmDRM_ENUM_NAME_FN(drm_get_dirty_info_name, 136874Sache drm_dirty_info_enum_list) 1371110Salm 13812724Sphkstruct drm_conn_prop_enum_list { 1394Srgrimes int type; 140890Sache char *name; 141890Sache int count; 142890Sache}; 143890Sache 144890Sache/* 145890Sache * Connector and encoder types. 146890Sache */ 1471233Sachestatic struct drm_conn_prop_enum_list drm_connector_enum_list[] = 148874Sache{ { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 }, 149890Sache { DRM_MODE_CONNECTOR_VGA, "VGA", 0 }, 150890Sache { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 }, 151890Sache { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 }, 152890Sache { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 }, 153890Sache { DRM_MODE_CONNECTOR_Composite, "Composite", 0 }, 154890Sache { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 }, 1554Srgrimes { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 }, 1564Srgrimes { DRM_MODE_CONNECTOR_Component, "Component", 0 }, 1571110Salm { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 }, 1585512Sjoerg { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 }, 1594Srgrimes { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 }, 1604Srgrimes { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, 1614Srgrimes { DRM_MODE_CONNECTOR_TV, "TV", 0 }, 1621110Salm { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, 1634Srgrimes}; 1644Srgrimes 1654Srgrimesstatic struct drm_prop_enum_list drm_encoder_enum_list[] = 1661110Salm{ { DRM_MODE_ENCODER_NONE, "None" }, 1674Srgrimes { DRM_MODE_ENCODER_DAC, "DAC" }, 16812724Sphk { DRM_MODE_ENCODER_TMDS, "TMDS" }, 1691110Salm { DRM_MODE_ENCODER_LVDS, "LVDS" }, 1704Srgrimes { DRM_MODE_ENCODER_TVDAC, "TV" }, 1712838Sdg}; 1724Srgrimes 1734Srgrimeschar *drm_get_encoder_name(struct drm_encoder *encoder) 1744Srgrimes{ 1754Srgrimes static char buf[32]; 1764Srgrimes 1774Srgrimes snprintf(buf, 32, "%s-%d", 1782838Sdg drm_encoder_enum_list[encoder->encoder_type].name, 1792838Sdg encoder->base.id); 1805417Sjoerg return buf; 1812838Sdg} 1822838Sdg 18329677Sgibbschar *drm_get_connector_name(struct drm_connector *connector) 18429677Sgibbs{ 18539228Sgibbs static char buf[32]; 18615108Sbde 18715108Sbde snprintf(buf, 32, "%s-%d", 18815108Sbde drm_connector_enum_list[connector->connector_type].name, 18912675Sjulian connector->connector_type_id); 1904Srgrimes return buf; 1914Srgrimes} 1924Srgrimes 1934Srgrimeschar *drm_get_connector_status_name(enum drm_connector_status status) 1944Srgrimes{ 1954Srgrimes if (status == connector_status_connected) 1964Srgrimes return "connected"; 1974Srgrimes else if (status == connector_status_disconnected) 1984Srgrimes return "disconnected"; 1994Srgrimes else 2004Srgrimes return "unknown"; 2012838Sdg} 2022838Sdg 2032838Sdg/** 2042838Sdg * drm_mode_object_get - allocate a new identifier 2052838Sdg * @dev: DRM device 20637677Sbde * @ptr: object pointer, used to generate unique ID 2072838Sdg * @type: object type 2082838Sdg * 2097643Srgrimes * LOCKING: 2102838Sdg * 2111110Salm * Create a unique identifier based on @ptr in @dev's identifier space. Used 21241693Simp * for tracking modes, CRTCs and connectors. 21341693Simp * 21441693Simp * RETURNS: 21541693Simp * New unique (relative to other objects in @dev) integer identifier for the 21641693Simp * object. 2172838Sdg */ 2182838Sdgstatic int drm_mode_object_get(struct drm_device *dev, 2192838Sdg struct drm_mode_object *obj, uint32_t obj_type) 2202838Sdg{ 2212838Sdg int new_id; 2222838Sdg int ret; 2232838Sdg 2242838Sdg new_id = 0; 2252838Sdg ret = drm_gem_name_create(&dev->mode_config.crtc_names, obj, &new_id); 2262838Sdg if (ret != 0) 2272838Sdg return (ret); 2282838Sdg 2292838Sdg obj->id = new_id; 2302838Sdg obj->type = obj_type; 2312838Sdg return 0; 2322838Sdg} 2337090Sbde 2342838Sdg/** 23537945Sbde * drm_mode_object_put - free an identifer 2362838Sdg * @dev: DRM device 23740565Sbde * @id: ID to free 2382838Sdg * 239879Swollman * LOCKING: 2402838Sdg * Caller must hold DRM mode_config lock. 241879Swollman * 24229543Stegge * Free @id from @dev's unique identifier pool. 2432838Sdg */ 24429543Steggestatic void drm_mode_object_put(struct drm_device *dev, 24529543Stegge struct drm_mode_object *object) 24629543Stegge{ 2474Srgrimes 2484Srgrimes drm_gem_names_remove(&dev->mode_config.crtc_names, object->id); 2494Srgrimes} 2504Srgrimes 2514Srgrimesstruct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 2524Srgrimes uint32_t id, uint32_t type) 2534Srgrimes{ 2544Srgrimes struct drm_mode_object *obj; 2554Srgrimes 2564Srgrimes obj = drm_gem_name_ref(&dev->mode_config.crtc_names, id, NULL); 2574Srgrimes if (!obj || (obj->type != type) || (obj->id != id)) 2584Srgrimes obj = NULL; 25937945Sbde 26041693Simp return obj; 26141693Simp} 26241693Simp 2634Srgrimes/** 26429494Sjoerg * drm_framebuffer_init - initialize a framebuffer 26517122Sbde * @dev: DRM device 2664Srgrimes * 2674Srgrimes * LOCKING: 2684Srgrimes * Caller must hold mode config lock. 2694Srgrimes * 2704Srgrimes * Allocates an ID for the framebuffer's parent mode object, sets its mode 2714Srgrimes * functions & device file and adds it to the master fd list. 2724Srgrimes * 2734Srgrimes * RETURNS: 2744Srgrimes * Zero on success, error code on failure. 2754Srgrimes */ 2764Srgrimesint drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 2774Srgrimes const struct drm_framebuffer_funcs *funcs) 27837945Sbde{ 27937945Sbde int ret; 28041693Simp 28141693Simp DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 28241693Simp 2834Srgrimes ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 2844Srgrimes if (ret) 2852838Sdg return ret; 28617122Sbde 2874Srgrimes fb->dev = dev; 2882838Sdg fb->funcs = funcs; 28929494Sjoerg dev->mode_config.num_fb++; 2904Srgrimes list_add(&fb->head, &dev->mode_config.fb_list); 2912838Sdg 29229494Sjoerg return 0; 2934Srgrimes} 29441693Simp 29541693Simp/** 29641693Simp * drm_framebuffer_cleanup - remove a framebuffer object 29741693Simp * @fb: framebuffer to remove 29841693Simp * 29941693Simp * LOCKING: 30041693Simp * Caller must hold mode config lock. 30141693Simp * 30241693Simp * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes 30341693Simp * it, setting it to NULL. 30441693Simp */ 30541693Simpvoid drm_framebuffer_cleanup(struct drm_framebuffer *fb) 30641693Simp{ 30741693Simp struct drm_device *dev = fb->dev; 30841693Simp struct drm_crtc *crtc; 30941693Simp struct drm_plane *plane; 31041693Simp struct drm_mode_set set; 31141693Simp int ret; 31241693Simp 31341693Simp DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 31441693Simp 31541693Simp /* remove from any CRTC */ 31641693Simp list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 31741693Simp if (crtc->fb == fb) { 31841693Simp /* should turn off the crtc */ 31941693Simp memset(&set, 0, sizeof(struct drm_mode_set)); 32041693Simp set.crtc = crtc; 32141693Simp set.fb = NULL; 32241693Simp ret = crtc->funcs->set_config(&set); 32341693Simp if (ret) 32441693Simp DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 32541693Simp } 32641693Simp } 32741693Simp 32841693Simp list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 32941693Simp if (plane->fb == fb) { 33041693Simp /* should turn off the crtc */ 33141693Simp ret = plane->funcs->disable_plane(plane); 33241693Simp if (ret) 33341693Simp DRM_ERROR("failed to disable plane with busy fb\n"); 33441693Simp /* disconnect the plane from the fb and crtc: */ 33541693Simp plane->fb = NULL; 33641693Simp plane->crtc = NULL; 33741693Simp } 33841693Simp } 33941693Simp 34041693Simp drm_mode_object_put(dev, &fb->base); 34141693Simp list_del(&fb->head); 34241693Simp dev->mode_config.num_fb--; 34341693Simp} 34441693Simp 34541693Simp/** 34641693Simp * drm_crtc_init - Initialise a new CRTC object 34741693Simp * @dev: DRM device 34841693Simp * @crtc: CRTC object to init 34941693Simp * @funcs: callbacks for the new CRTC 35041693Simp * 35141693Simp * LOCKING: 35241693Simp * Caller must hold mode config lock. 35341693Simp * 35441693Simp * Inits a new object created as base part of an driver crtc object. 35541693Simp * 35641693Simp * RETURNS: 35741693Simp * Zero on success, error code on failure. 35841693Simp */ 35941693Simpint drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 36041693Simp const struct drm_crtc_funcs *funcs) 36141693Simp{ 36241693Simp int ret; 36341693Simp 36441693Simp crtc->dev = dev; 36541693Simp crtc->funcs = funcs; 36641693Simp 36741693Simp sx_xlock(&dev->mode_config.mutex); 36841693Simp ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 36941693Simp if (ret) 37041693Simp goto out; 37141693Simp 37241693Simp list_add_tail(&crtc->head, &dev->mode_config.crtc_list); 37341693Simp dev->mode_config.num_crtc++; 37441693Simpout: 37541693Simp sx_xunlock(&dev->mode_config.mutex); 37641693Simp 37741693Simp return ret; 37841693Simp} 37941693Simp 38041693Simp/** 38141693Simp * drm_crtc_cleanup - Cleans up the core crtc usage. 38241693Simp * @crtc: CRTC to cleanup 38341693Simp * 38441693Simp * LOCKING: 38541693Simp * Caller must hold mode config lock. 38641693Simp * 3875512Sjoerg * Cleanup @crtc. Removes from drm modesetting space 3885512Sjoerg * does NOT free object, caller does that. 3895512Sjoerg */ 3905512Sjoergvoid drm_crtc_cleanup(struct drm_crtc *crtc) 3915512Sjoerg{ 3925512Sjoerg struct drm_device *dev = crtc->dev; 39312675Sjulian 39437389Sjulian DRM_MODE_CONFIG_ASSERT_LOCKED(dev); 39537389Sjulian 39612675Sjulian if (crtc->gamma_store) { 39712675Sjulian free(crtc->gamma_store, DRM_MEM_KMS); 39812675Sjulian crtc->gamma_store = NULL; 39912675Sjulian } 40035319Sjulian 40112675Sjulian drm_mode_object_put(dev, &crtc->base); 40212675Sjulian list_del(&crtc->head); 40312675Sjulian dev->mode_config.num_crtc--; 40412675Sjulian} 40537389Sjulian 40637389Sjulian/** 40737389Sjulian * drm_mode_probed_add - add a mode to a connector's probed mode list 40837389Sjulian * @connector: connector the new mode 40937389Sjulian * @mode: mode data 41037389Sjulian * 41137389Sjulian * LOCKING: 41237389Sjulian * Caller must hold mode config lock. 41312724Sphk * 4143705Swollman * Add @mode to @connector's mode list for later use. 41535319Sjulian */ 4163705Swollmanvoid drm_mode_probed_add(struct drm_connector *connector, 4175417Sjoerg struct drm_display_mode *mode) 4185417Sjoerg{ 4195417Sjoerg 42011162Sjoerg DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); 42111162Sjoerg 42211162Sjoerg list_add(&mode->head, &connector->probed_modes); 42311162Sjoerg} 42411162Sjoerg 42541693Simp/** 42611162Sjoerg * drm_mode_remove - remove and free a mode 4278876Srgrimes * @connector: connector list to modify 4285417Sjoerg * @mode: mode to remove 4295417Sjoerg * 4305417Sjoerg * LOCKING: 4315417Sjoerg * Caller must hold mode config lock. 4325417Sjoerg * 4335417Sjoerg * Remove @mode from @connector's mode list, then free it. 4345417Sjoerg */ 4358876Srgrimesvoid drm_mode_remove(struct drm_connector *connector, 4365417Sjoerg struct drm_display_mode *mode) 4375417Sjoerg{ 43812724Sphk 4395417Sjoerg DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); 4405417Sjoerg 4415417Sjoerg list_del(&mode->head); 4425417Sjoerg drm_mode_destroy(connector->dev, mode); 4435417Sjoerg} 4445417Sjoerg 4455417Sjoerg/** 4465417Sjoerg * drm_connector_init - Init a preallocated connector 4475417Sjoerg * @dev: DRM device 4485417Sjoerg * @connector: the connector to init 4495417Sjoerg * @funcs: callbacks for this connector 4505417Sjoerg * @name: user visible name of the connector 4515417Sjoerg * 4525417Sjoerg * LOCKING: 4535417Sjoerg * Takes mode config lock. 4545417Sjoerg * 45541514Sarchie * Initialises a preallocated connector. Connectors should be 4565417Sjoerg * subclassed as part of driver connector objects. 4575417Sjoerg * 4585417Sjoerg * RETURNS: 4595417Sjoerg * Zero on success, error code on failure. 4605417Sjoerg */ 4615417Sjoergint drm_connector_init(struct drm_device *dev, 4625417Sjoerg struct drm_connector *connector, 4635417Sjoerg const struct drm_connector_funcs *funcs, 4645417Sjoerg int connector_type) 4655417Sjoerg{ 4665417Sjoerg int ret; 4675417Sjoerg 46841514Sarchie sx_xlock(&dev->mode_config.mutex); 4695417Sjoerg 4705417Sjoerg ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); 4715417Sjoerg if (ret) 4725417Sjoerg goto out; 4735417Sjoerg 4745417Sjoerg connector->dev = dev; 4755417Sjoerg connector->funcs = funcs; 4765417Sjoerg connector->connector_type = connector_type; 4775417Sjoerg connector->connector_type_id = 47829543Stegge ++drm_connector_enum_list[connector_type].count; /* TODO */ 47929543Stegge INIT_LIST_HEAD(&connector->user_modes); 48029543Stegge INIT_LIST_HEAD(&connector->probed_modes); 48129543Stegge INIT_LIST_HEAD(&connector->modes); 48229543Stegge connector->edid_blob_ptr = NULL; 48329543Stegge 48429543Stegge list_add_tail(&connector->head, &dev->mode_config.connector_list); 48529543Stegge dev->mode_config.num_connector++; 48629543Stegge 48729543Stegge drm_connector_attach_property(connector, 48829543Stegge dev->mode_config.edid_property, 0); 48929543Stegge 49029543Stegge drm_connector_attach_property(connector, 49129543Stegge dev->mode_config.dpms_property, 0); 49229543Stegge 49329543Steggeout: 49429543Stegge sx_xunlock(&dev->mode_config.mutex); 49529543Stegge 49629543Stegge return ret; 49729543Stegge} 49829543Stegge 49929543Stegge/** 50029543Stegge * drm_connector_cleanup - cleans up an initialised connector 50129543Stegge * @connector: connector to cleanup 50229543Stegge * 50329543Stegge * LOCKING: 50429543Stegge * Takes mode config lock. 50529543Stegge * 50629543Stegge * Cleans up the connector but doesn't free the object. 50729543Stegge */ 50829543Steggevoid drm_connector_cleanup(struct drm_connector *connector) 50929543Stegge{ 51029543Stegge struct drm_device *dev = connector->dev; 51129543Stegge struct drm_display_mode *mode, *t; 51229543Stegge 51329543Stegge list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 51429543Stegge drm_mode_remove(connector, mode); 51529543Stegge 51629543Stegge list_for_each_entry_safe(mode, t, &connector->modes, head) 51729543Stegge drm_mode_remove(connector, mode); 51812724Sphk 5195417Sjoerg list_for_each_entry_safe(mode, t, &connector->user_modes, head) 5205417Sjoerg drm_mode_remove(connector, mode); 5215417Sjoerg 5225417Sjoerg sx_xlock(&dev->mode_config.mutex); 5235417Sjoerg drm_mode_object_put(dev, &connector->base); 5245417Sjoerg list_del(&connector->head); 5257393Srgrimes dev->mode_config.num_connector--; 5265417Sjoerg sx_xunlock(&dev->mode_config.mutex); 5275417Sjoerg} 5285417Sjoerg 5295417Sjoergint drm_encoder_init(struct drm_device *dev, 5305417Sjoerg struct drm_encoder *encoder, 5315417Sjoerg const struct drm_encoder_funcs *funcs, 5325417Sjoerg int encoder_type) 53312724Sphk{ 5345417Sjoerg int ret; 5355417Sjoerg 5365417Sjoerg sx_xlock(&dev->mode_config.mutex); 5375417Sjoerg 5385417Sjoerg ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 5395417Sjoerg if (ret) 5405417Sjoerg goto out; 5415417Sjoerg 5425417Sjoerg encoder->dev = dev; 5435417Sjoerg encoder->encoder_type = encoder_type; 5445417Sjoerg encoder->funcs = funcs; 5455417Sjoerg 5465417Sjoerg list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 5475417Sjoerg dev->mode_config.num_encoder++; 5485417Sjoerg 5495417Sjoergout: 5505417Sjoerg sx_xunlock(&dev->mode_config.mutex); 5515417Sjoerg 5525417Sjoerg return ret; 5535417Sjoerg} 5545417Sjoerg 5555417Sjoergvoid drm_encoder_cleanup(struct drm_encoder *encoder) 5565417Sjoerg{ 5575417Sjoerg struct drm_device *dev = encoder->dev; 5585417Sjoerg 5595417Sjoerg sx_xlock(&dev->mode_config.mutex); 5605417Sjoerg drm_mode_object_put(dev, &encoder->base); 5615417Sjoerg list_del(&encoder->head); 5625417Sjoerg dev->mode_config.num_encoder--; 5635417Sjoerg sx_xunlock(&dev->mode_config.mutex); 5645417Sjoerg} 5655417Sjoerg 5665417Sjoergint drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 5675417Sjoerg unsigned long possible_crtcs, 5685417Sjoerg const struct drm_plane_funcs *funcs, 5695417Sjoerg const uint32_t *formats, uint32_t format_count, 57012724Sphk bool priv) 5715417Sjoerg{ 5725417Sjoerg int ret; 5735417Sjoerg 5747090Sbde sx_xlock(&dev->mode_config.mutex); 5755417Sjoerg 5765417Sjoerg ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 5777090Sbde if (ret) 5787090Sbde goto out; 57937554Sbde 5807090Sbde plane->dev = dev; 5817090Sbde plane->funcs = funcs; 5827090Sbde plane->format_types = malloc(sizeof(uint32_t) * format_count, 5837090Sbde DRM_MEM_KMS, M_WAITOK); 5847090Sbde 5857090Sbde memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 5867090Sbde plane->format_count = format_count; 5875417Sjoerg plane->possible_crtcs = possible_crtcs; 5885417Sjoerg 5895417Sjoerg /* private planes are not exposed to userspace, but depending on 5905417Sjoerg * display hardware, might be convenient to allow sharing programming 5915417Sjoerg * for the scanout engine with the crtc implementation. 5925417Sjoerg */ 5935417Sjoerg if (!priv) { 5945417Sjoerg list_add_tail(&plane->head, &dev->mode_config.plane_list); 5955417Sjoerg dev->mode_config.num_plane++; 5965417Sjoerg } else { 5975417Sjoerg INIT_LIST_HEAD(&plane->head); 5984Srgrimes } 5994Srgrimes 6004Srgrimesout: 6014Srgrimes sx_xunlock(&dev->mode_config.mutex); 6024Srgrimes 6034Srgrimes return ret; 6044Srgrimes} 6052838Sdg 6065417Sjoergvoid drm_plane_cleanup(struct drm_plane *plane) 6074Srgrimes{ 6084Srgrimes struct drm_device *dev = plane->dev; 6094Srgrimes 6104Srgrimes sx_xlock(&dev->mode_config.mutex); 6117393Srgrimes free(plane->format_types, DRM_MEM_KMS); 6124Srgrimes drm_mode_object_put(dev, &plane->base); 6134Srgrimes /* if not added to a list, it must be a private plane */ 6144Srgrimes if (!list_empty(&plane->head)) { 6153705Swollman list_del(&plane->head); 6164Srgrimes dev->mode_config.num_plane--; 6174Srgrimes } 618826Salm sx_xunlock(&dev->mode_config.mutex); 6192838Sdg} 620826Salm 6212838Sdg/** 622826Salm * drm_mode_create - create a new display mode 6234Srgrimes * @dev: DRM device 6245417Sjoerg * 6255417Sjoerg * LOCKING: 6265417Sjoerg * Caller must hold DRM mode_config lock. 6274Srgrimes * 6284Srgrimes * Create a new drm_display_mode, give it an ID, and return it. 6294Srgrimes * 63041693Simp * RETURNS: 63141693Simp * Pointer to new mode on success, NULL on error. 63241693Simp */ 63341693Simpstruct drm_display_mode *drm_mode_create(struct drm_device *dev) 63441693Simp{ 63541693Simp struct drm_display_mode *nmode; 63641693Simp 63741693Simp nmode = malloc(sizeof(struct drm_display_mode), DRM_MEM_KMS, 6384Srgrimes M_WAITOK | M_ZERO); 6394Srgrimes 6404Srgrimes if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { 6414Srgrimes free(nmode, DRM_MEM_KMS); 6424Srgrimes return (NULL); 6434Srgrimes } 6442838Sdg return nmode; 6455417Sjoerg} 6464Srgrimes 6472838Sdg/** 6484Srgrimes * drm_mode_destroy - remove a mode 6494Srgrimes * @dev: DRM device 6504Srgrimes * @mode: mode to remove 6514Srgrimes * 65217122Sbde * LOCKING: 65317122Sbde * Caller must hold mode config lock. 65417122Sbde * 65517122Sbde * Free @mode's unique identifier, then free it. 6561110Salm */ 6575417Sjoergvoid drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) 65815108Sbde{ 65913647Sbde if (!mode) 66015108Sbde return; 66115108Sbde 66215108Sbde drm_mode_object_put(dev, &mode->base); 6634Srgrimes 66440565Sbde free(mode, DRM_MEM_KMS); 6654Srgrimes} 6664Srgrimes 6674Srgrimesstatic int drm_mode_create_standard_connector_properties(struct drm_device *dev) 66815148Ssmpatel{ 66915148Ssmpatel struct drm_property *edid; 67013646Sbde struct drm_property *dpms; 6714Srgrimes 6722838Sdg /* 6732838Sdg * Standard properties (apply to all connectors) 67429677Sgibbs */ 6754Srgrimes edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | 6764Srgrimes DRM_MODE_PROP_IMMUTABLE, 6771110Salm "EDID", 0); 6781110Salm dev->mode_config.edid_property = edid; 6791110Salm 6801110Salm dpms = drm_property_create_enum(dev, 0, 6811110Salm "DPMS", drm_dpms_enum_list, 6821110Salm DRM_ARRAY_SIZE(drm_dpms_enum_list)); 6831110Salm dev->mode_config.dpms_property = dpms; 6841110Salm 6855417Sjoerg return 0; 6861110Salm} 68730574Sjoerg 68830574Sjoerg/** 68930574Sjoerg * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 69030574Sjoerg * @dev: DRM device 6911110Salm * 6921110Salm * Called by a driver the first time a DVI-I connector is made. 6931110Salm */ 6941110Salmint drm_mode_create_dvi_i_properties(struct drm_device *dev) 6951110Salm{ 6961110Salm struct drm_property *dvi_i_selector; 6974Srgrimes struct drm_property *dvi_i_subconnector; 6981110Salm 6991110Salm if (dev->mode_config.dvi_i_select_subconnector_property) 7005512Sjoerg return 0; 7011110Salm 7021110Salm dvi_i_selector = 7031231Salm drm_property_create_enum(dev, 0, 7041110Salm "select subconnector", 7051110Salm drm_dvi_i_select_enum_list, 7064874Sjkh DRM_ARRAY_SIZE(drm_dvi_i_select_enum_list)); 7074874Sjkh dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 7087643Srgrimes 7097643Srgrimes dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 7107643Srgrimes "subconnector", 7117643Srgrimes drm_dvi_i_subconnector_enum_list, 7127643Srgrimes DRM_ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 7137643Srgrimes dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 7148310Sjoerg 7151110Salm return 0; 7168876Srgrimes} 7171231Salm 7181110Salm/** 7194Srgrimes * drm_create_tv_properties - create TV specific connector properties 720464Sjkh * @dev: DRM device 7214Srgrimes * @num_modes: number of different TV formats (modes) supported 7224Srgrimes * @modes: array of pointers to strings containing name of each format 7232838Sdg * 7242841Sjoerg * Called by a driver's TV initialization routine, this function creates 7255417Sjoerg * the TV specific connector properties for a given device. Caller is 7265417Sjoerg * responsible for allocating a list of format names and passing them to 7275417Sjoerg * this routine. 7285417Sjoerg */ 72929494Sjoergint drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, 7307393Srgrimes char *modes[]) 73129494Sjoerg{ 7325417Sjoerg struct drm_property *tv_selector; 7335417Sjoerg struct drm_property *tv_subconnector; 7345417Sjoerg int i; 73529494Sjoerg 7367393Srgrimes if (dev->mode_config.tv_select_subconnector_property) 73729494Sjoerg return 0; 7385417Sjoerg 7395417Sjoerg /* 7405417Sjoerg * Basic connector properties 74129494Sjoerg */ 7427393Srgrimes tv_selector = drm_property_create_enum(dev, 0, 74329494Sjoerg "select subconnector", 7445417Sjoerg drm_tv_select_enum_list, 7455417Sjoerg DRM_ARRAY_SIZE(drm_tv_select_enum_list)); 7465417Sjoerg dev->mode_config.tv_select_subconnector_property = tv_selector; 74729494Sjoerg 7487393Srgrimes tv_subconnector = 74929494Sjoerg drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 7505417Sjoerg "subconnector", 7515417Sjoerg drm_tv_subconnector_enum_list, 7525417Sjoerg DRM_ARRAY_SIZE(drm_tv_subconnector_enum_list)); 75329494Sjoerg dev->mode_config.tv_subconnector_property = tv_subconnector; 7547393Srgrimes 75529494Sjoerg /* 7565417Sjoerg * Other, TV specific properties: margins & TV modes. 7575417Sjoerg */ 7585417Sjoerg dev->mode_config.tv_left_margin_property = 75929543Stegge drm_property_create_range(dev, 0, "left margin", 0, 100); 76029543Stegge 76129543Stegge dev->mode_config.tv_right_margin_property = 76229543Stegge drm_property_create_range(dev, 0, "right margin", 0, 100); 76329543Stegge 76441693Simp dev->mode_config.tv_top_margin_property = 76529543Stegge drm_property_create_range(dev, 0, "top margin", 0, 100); 7665417Sjoerg 7675417Sjoerg dev->mode_config.tv_bottom_margin_property = 7685417Sjoerg drm_property_create_range(dev, 0, "bottom margin", 0, 100); 7692841Sjoerg 7705417Sjoerg dev->mode_config.tv_mode_property = 7715417Sjoerg drm_property_create(dev, DRM_MODE_PROP_ENUM, 7722841Sjoerg "mode", num_modes); 7735417Sjoerg for (i = 0; i < num_modes; i++) 7742841Sjoerg drm_property_add_enum(dev->mode_config.tv_mode_property, i, 7755417Sjoerg i, modes[i]); 7765417Sjoerg 7775417Sjoerg dev->mode_config.tv_brightness_property = 7785417Sjoerg drm_property_create_range(dev, 0, "brightness", 0, 100); 7795417Sjoerg 7805417Sjoerg dev->mode_config.tv_contrast_property = 7815417Sjoerg drm_property_create_range(dev, 0, "contrast", 0, 100); 7825417Sjoerg 7835417Sjoerg dev->mode_config.tv_flicker_reduction_property = 7845417Sjoerg drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 7855417Sjoerg 7865417Sjoerg dev->mode_config.tv_overscan_property = 7875417Sjoerg drm_property_create_range(dev, 0, "overscan", 0, 100); 7882841Sjoerg 7892841Sjoerg dev->mode_config.tv_saturation_property = 7902841Sjoerg drm_property_create_range(dev, 0, "saturation", 0, 100); 7912841Sjoerg 7922841Sjoerg dev->mode_config.tv_hue_property = 7932841Sjoerg drm_property_create_range(dev, 0, "hue", 0, 100); 7942841Sjoerg 7955417Sjoerg return 0; 7965417Sjoerg} 7975417Sjoerg 7985417Sjoerg/** 7994Srgrimes * drm_mode_create_scaling_mode_property - create scaling mode property 8005417Sjoerg * @dev: DRM device 8015417Sjoerg * 8025417Sjoerg * Called by a driver the first time it's needed, must be attached to desired 8035417Sjoerg * connectors. 8045417Sjoerg */ 8052841Sjoergint drm_mode_create_scaling_mode_property(struct drm_device *dev) 8068876Srgrimes{ 8072838Sdg struct drm_property *scaling_mode; 8088876Srgrimes 8092838Sdg if (dev->mode_config.scaling_mode_property) 8104Srgrimes return 0; 8114Srgrimes 8125417Sjoerg scaling_mode = 8131110Salm drm_property_create_enum(dev, 0, "scaling mode", 8141110Salm drm_scaling_mode_enum_list, 8152838Sdg DRM_ARRAY_SIZE(drm_scaling_mode_enum_list)); 81629677Sgibbs 81729677Sgibbs dev->mode_config.scaling_mode_property = scaling_mode; 8188376Srgrimes 8198876Srgrimes return 0; 8201110Salm} 821863Sache 8227393Srgrimes/** 8231110Salm * drm_mode_create_dithering_property - create dithering property 824863Sache * @dev: DRM device 82530574Sjoerg * 82630574Sjoerg * Called by a driver the first time it's needed, must be attached to desired 82730574Sjoerg * connectors. 82830574Sjoerg */ 829863Sacheint drm_mode_create_dithering_property(struct drm_device *dev) 8307393Srgrimes{ 8311110Salm struct drm_property *dithering_mode; 832863Sache 8334968Sjoerg if (dev->mode_config.dithering_mode_property) 83411375Sjoerg return 0; 8357393Srgrimes 8364968Sjoerg dithering_mode = 8374968Sjoerg drm_property_create_enum(dev, 0, "dithering", 838863Sache drm_dithering_mode_enum_list, 8397393Srgrimes DRM_ARRAY_SIZE(drm_dithering_mode_enum_list)); 8401110Salm dev->mode_config.dithering_mode_property = dithering_mode; 841863Sache 842874Sache return 0; 8437393Srgrimes} 8441110Salm 845874Sache/** 846863Sache * drm_mode_create_dirty_property - create dirty property 8477393Srgrimes * @dev: DRM device 8481110Salm * 84915108Sbde * Called by a driver the first time it's needed, must be attached to desired 850854Sache * connectors. 8517945Sjulian */ 85215108Sbdeint drm_mode_create_dirty_info_property(struct drm_device *dev) 85337389Sjulian{ 85415108Sbde struct drm_property *dirty_info; 85515108Sbde 85615108Sbde if (dev->mode_config.dirty_info_property) 85715108Sbde return 0; 85815108Sbde 85915108Sbde dirty_info = 86015108Sbde drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 86115108Sbde "dirty", 86215108Sbde drm_dirty_info_enum_list, 86315108Sbde DRM_ARRAY_SIZE(drm_dirty_info_enum_list)); 86415108Sbde dev->mode_config.dirty_info_property = dirty_info; 86515108Sbde 86615108Sbde return 0; 86715108Sbde} 86815108Sbde 86915108Sbde/** 87015108Sbde * drm_mode_config_init - initialize DRM mode_configuration structure 87115108Sbde * @dev: DRM device 87215108Sbde * 87315108Sbde * LOCKING: 87415108Sbde * None, should happen single threaded at init time. 87515108Sbde * 87615108Sbde * Initialize @dev's mode_config structure, used for tracking the graphics 87715108Sbde * configuration of @dev. 87815108Sbde */ 87915108Sbdevoid drm_mode_config_init(struct drm_device *dev) 88015108Sbde{ 88115108Sbde sx_init(&dev->mode_config.mutex, "kmslk"); 88215108Sbde INIT_LIST_HEAD(&dev->mode_config.fb_list); 88315108Sbde INIT_LIST_HEAD(&dev->mode_config.crtc_list); 88415108Sbde INIT_LIST_HEAD(&dev->mode_config.connector_list); 88515108Sbde INIT_LIST_HEAD(&dev->mode_config.encoder_list); 88615108Sbde INIT_LIST_HEAD(&dev->mode_config.property_list); 88715108Sbde INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 88815108Sbde INIT_LIST_HEAD(&dev->mode_config.plane_list); 88915108Sbde drm_gem_names_init(&dev->mode_config.crtc_names); 89015108Sbde 89115108Sbde sx_xlock(&dev->mode_config.mutex); 89215108Sbde drm_mode_create_standard_connector_properties(dev); 89315108Sbde sx_xunlock(&dev->mode_config.mutex); 89415108Sbde 89535319Sjulian /* Just to be sure */ 89615108Sbde dev->mode_config.num_fb = 0; 89737389Sjulian dev->mode_config.num_connector = 0; 89815108Sbde dev->mode_config.num_crtc = 0; 89915108Sbde dev->mode_config.num_encoder = 0; 90015108Sbde} 90115108Sbde 90215108Sbdestatic int 90315108Sbdedrm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 90415108Sbde{ 90535319Sjulian uint32_t total_objects = 0; 90615108Sbde 90741658Seivind total_objects += dev->mode_config.num_crtc; 90815108Sbde total_objects += dev->mode_config.num_connector; 90915108Sbde total_objects += dev->mode_config.num_encoder; 91041658Seivind 91115108Sbde group->id_list = malloc(total_objects * sizeof(uint32_t), 91215108Sbde DRM_MEM_KMS, M_WAITOK | M_ZERO); 9137945Sjulian 91439228Sgibbs group->num_crtcs = 0; 91539228Sgibbs group->num_connectors = 0; 91639228Sgibbs group->num_encoders = 0; 91739228Sgibbs return 0; 91839228Sgibbs} 91939228Sgibbs 92039228Sgibbsint drm_mode_group_init_legacy_group(struct drm_device *dev, 92139228Sgibbs struct drm_mode_group *group) 9224Srgrimes{ 9234Srgrimes struct drm_crtc *crtc; 9242838Sdg struct drm_encoder *encoder; 9254Srgrimes struct drm_connector *connector; 9264Srgrimes int ret; 92735319Sjulian 92835319Sjulian if ((ret = drm_mode_group_init(dev, group))) 92941693Simp return ret; 93041693Simp 93141693Simp list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 93241693Simp group->id_list[group->num_crtcs++] = crtc->base.id; 93341693Simp 93441693Simp list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 93541693Simp group->id_list[group->num_crtcs + group->num_encoders++] = 93641693Simp encoder->base.id; 93741693Simp 93841693Simp list_for_each_entry(connector, &dev->mode_config.connector_list, head) 93941693Simp group->id_list[group->num_crtcs + group->num_encoders + 94041693Simp group->num_connectors++] = connector->base.id; 94141693Simp 94241693Simp return 0; 94341693Simp} 94441693Simp 94541693Simp/** 94641693Simp * drm_mode_config_cleanup - free up DRM mode_config info 94741693Simp * @dev: DRM device 94841693Simp * 94941693Simp * LOCKING: 95041693Simp * Caller must hold mode config lock. 95141693Simp * 95241693Simp * Free up all the connectors and CRTCs associated with this DRM device, then 95341693Simp * free up the framebuffers and associated buffer objects. 95441693Simp * 95541693Simp * FIXME: cleanup any dangling user buffer objects too 95641693Simp */ 95741693Simpvoid drm_mode_config_cleanup(struct drm_device *dev) 95841693Simp{ 95941693Simp struct drm_connector *connector, *ot; 96041693Simp struct drm_crtc *crtc, *ct; 96141693Simp struct drm_encoder *encoder, *enct; 96241693Simp struct drm_framebuffer *fb, *fbt; 96341693Simp struct drm_property *property, *pt; 96441693Simp struct drm_plane *plane, *plt; 96541693Simp 96641693Simp list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 96741693Simp head) { 96841693Simp encoder->funcs->destroy(encoder); 96941693Simp } 97041693Simp 97141693Simp list_for_each_entry_safe(connector, ot, 97241693Simp &dev->mode_config.connector_list, head) { 97341693Simp connector->funcs->destroy(connector); 97441693Simp } 97541693Simp 97641693Simp list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 97741693Simp head) { 97841693Simp drm_property_destroy(dev, property); 97941693Simp } 98041693Simp 98141693Simp list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 98241693Simp fb->funcs->destroy(fb); 98341693Simp } 98441693Simp 98541693Simp list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 98641693Simp crtc->funcs->destroy(crtc); 98741693Simp } 98841693Simp 98941693Simp list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 99041693Simp head) { 99141693Simp plane->funcs->destroy(plane); 99241693Simp } 99341693Simp drm_gem_names_fini(&dev->mode_config.crtc_names); 99441693Simp} 99541693Simp 99641693Simp/** 99741693Simp * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 99841693Simp * @out: drm_mode_modeinfo struct to return to the user 99941693Simp * @in: drm_display_mode to use 100041693Simp * 100141693Simp * LOCKING: 100241693Simp * None. 100341693Simp * 100441693Simp * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 100541693Simp * the user. 100641693Simp */ 100741693Simpstatic void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 100841693Simp const struct drm_display_mode *in) 100941693Simp{ 101041693Simp if (in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 101141693Simp in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 101241693Simp in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 101341693Simp in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 101441693Simp in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX) 101541693Simp printf("timing values too large for mode info\n"); 101641693Simp 101741693Simp out->clock = in->clock; 101841693Simp out->hdisplay = in->hdisplay; 101941693Simp out->hsync_start = in->hsync_start; 102041693Simp out->hsync_end = in->hsync_end; 102141693Simp out->htotal = in->htotal; 102241693Simp out->hskew = in->hskew; 102341693Simp out->vdisplay = in->vdisplay; 102441693Simp out->vsync_start = in->vsync_start; 102541693Simp out->vsync_end = in->vsync_end; 102641693Simp out->vtotal = in->vtotal; 102741693Simp out->vscan = in->vscan; 102841693Simp out->vrefresh = in->vrefresh; 102941693Simp out->flags = in->flags; 103041693Simp out->type = in->type; 103141693Simp strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 103241693Simp out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 103341693Simp} 103441693Simp 103541693Simp/** 103641693Simp * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode 103741693Simp * @out: drm_display_mode to return to the user 103841693Simp * @in: drm_mode_modeinfo to use 103941693Simp * 104041693Simp * LOCKING: 104141693Simp * None. 104241693Simp * 104341693Simp * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 104441693Simp * the caller. 104541693Simp * 104641693Simp * RETURNS: 104741693Simp * Zero on success, errno on failure. 104841693Simp */ 104941693Simpstatic int drm_crtc_convert_umode(struct drm_display_mode *out, 105041693Simp const struct drm_mode_modeinfo *in) 105141693Simp{ 105241693Simp if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 105341693Simp return ERANGE; 105441693Simp 105541693Simp out->clock = in->clock; 105641693Simp out->hdisplay = in->hdisplay; 105741693Simp out->hsync_start = in->hsync_start; 105841693Simp out->hsync_end = in->hsync_end; 105941693Simp out->htotal = in->htotal; 106041693Simp out->hskew = in->hskew; 10614Srgrimes out->vdisplay = in->vdisplay; 10622838Sdg out->vsync_start = in->vsync_start; 10634088Sjkh out->vsync_end = in->vsync_end; 10644Srgrimes out->vtotal = in->vtotal; 10652838Sdg out->vscan = in->vscan; 10665417Sjoerg out->vrefresh = in->vrefresh; 10674Srgrimes out->flags = in->flags; 10682838Sdg out->type = in->type; 10692838Sdg strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 10708876Srgrimes out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 10712838Sdg 10728876Srgrimes return 0; 10732838Sdg} 10742838Sdg 10752838Sdg/** 10764Srgrimes * drm_mode_getresources - get graphics configuration 10774088Sjkh * @inode: inode from the ioctl 10784088Sjkh * @filp: file * from the ioctl 10794088Sjkh * @cmd: cmd from ioctl 10804088Sjkh * @arg: arg from ioctl 10814088Sjkh * 10822838Sdg * LOCKING: 10832838Sdg * Takes mode config lock. 10842838Sdg * 10852838Sdg * Construct a set of configuration description structures and return 10864Srgrimes * them to the user, including CRTC, connector and framebuffer configuration. 10874Srgrimes * 10882838Sdg * Called by the user via ioctl. 10892838Sdg * 10902838Sdg * RETURNS: 10914Srgrimes * Zero on success, errno on failure. 10922838Sdg */ 10933755Sjoergint drm_mode_getresources(struct drm_device *dev, void *data, 10945417Sjoerg struct drm_file *file_priv) 10953755Sjoerg{ 10963755Sjoerg struct drm_mode_card_res *card_res = data; 10973755Sjoerg struct list_head *lh; 10983755Sjoerg struct drm_framebuffer *fb; 10995417Sjoerg struct drm_connector *connector; 11005417Sjoerg struct drm_crtc *crtc; 11015417Sjoerg struct drm_encoder *encoder; 110229543Stegge int ret = 0; 110329543Stegge int connector_count = 0; 11044Srgrimes int crtc_count = 0; 11054Srgrimes int fb_count = 0; 11064Srgrimes int encoder_count = 0; 1107798Swollman int copied = 0, i; 11082234Spaul uint32_t __user *fb_id; 11094Srgrimes uint32_t __user *crtc_id; 1110798Swollman uint32_t __user *connector_id; 1111464Sjkh uint32_t __user *encoder_id; 11125512Sjoerg struct drm_mode_group *mode_group; 1113464Sjkh 11145512Sjoerg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 111514254Sbde return (EINVAL); 111614254Sbde 111714254Sbde sx_xlock(&dev->mode_config.mutex); 111814254Sbde 111914254Sbde /* 112014254Sbde * For the non-control nodes we need to limit the list of resources 112114254Sbde * by IDs in the group list for this node 112229677Sgibbs */ 112314254Sbde list_for_each(lh, &file_priv->fbs) 112414254Sbde fb_count++; 112514254Sbde 1126464Sjkh#if 1 11274Srgrimes mode_group = NULL; /* XXXKIB */ 11282838Sdg if (1 || file_priv->master) { 1129464Sjkh#else 11304Srgrimes mode_group = &file_priv->masterp->minor->mode_group; 11314Srgrimes if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 11322838Sdg#endif 11332234Spaul 11344Srgrimes list_for_each(lh, &dev->mode_config.crtc_list) 1135798Swollman crtc_count++; 1136464Sjkh 1137464Sjkh list_for_each(lh, &dev->mode_config.connector_list) 11384Srgrimes connector_count++; 1139464Sjkh 11404Srgrimes list_for_each(lh, &dev->mode_config.encoder_list) 11414Srgrimes encoder_count++; 11424Srgrimes } else { 1143464Sjkh 11444Srgrimes crtc_count = mode_group->num_crtcs; 1145464Sjkh connector_count = mode_group->num_connectors; 11464Srgrimes encoder_count = mode_group->num_encoders; 11474Srgrimes } 11482838Sdg 11498876Srgrimes card_res->max_height = dev->mode_config.max_height; 11504Srgrimes card_res->min_height = dev->mode_config.min_height; 11514Srgrimes card_res->max_width = dev->mode_config.max_width; 11524Srgrimes card_res->min_width = dev->mode_config.min_width; 11534Srgrimes 11542838Sdg /* handle this in 4 parts */ 11552838Sdg /* FBs */ 11564088Sjkh if (card_res->count_fbs >= fb_count) { 11574Srgrimes copied = 0; 11584Srgrimes fb_id = (uint32_t *)(uintptr_t)card_res->fb_id_ptr; 11594Srgrimes list_for_each_entry(fb, &file_priv->fbs, filp_head) { 1160798Swollman if (copyout(&fb->base.id, fb_id + copied, 11615417Sjoerg sizeof(uint32_t))) { 11624Srgrimes ret = EFAULT; 11632838Sdg goto out; 11648876Srgrimes } 11652838Sdg copied++; 11662838Sdg } 11672838Sdg } 11682838Sdg card_res->count_fbs = fb_count; 11692838Sdg 11702838Sdg /* CRTCs */ 11712838Sdg if (card_res->count_crtcs >= crtc_count) { 11722838Sdg copied = 0; 11732838Sdg crtc_id = (uint32_t *)(uintptr_t)card_res->crtc_id_ptr; 11742838Sdg#if 1 11752838Sdg if (1 || file_priv->master) { 11765417Sjoerg#else 11775417Sjoerg if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 11785417Sjoerg#endif 11795417Sjoerg list_for_each_entry(crtc, &dev->mode_config.crtc_list, 118029543Stegge head) { 118129543Stegge DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 11824Srgrimes if (copyout(&crtc->base.id, crtc_id + 11834Srgrimes copied, sizeof(uint32_t))) { 11844Srgrimes ret = EFAULT; 11854Srgrimes goto out; 11864Srgrimes } 11874Srgrimes copied++; 11885417Sjoerg } 11894Srgrimes } else { 11904Srgrimes for (i = 0; i < mode_group->num_crtcs; i++) { 11914Srgrimes if (copyout(&mode_group->id_list[i], 11922838Sdg crtc_id + copied, sizeof(uint32_t))) { 11934Srgrimes ret = EFAULT; 11945417Sjoerg goto out; 11957393Srgrimes } 11964Srgrimes copied++; 119711162Sjoerg } 119829494Sjoerg } 11992838Sdg } 12002838Sdg card_res->count_crtcs = crtc_count; 12014Srgrimes 120229494Sjoerg /* Encoders */ 12032838Sdg if (card_res->count_encoders >= encoder_count) { 120429494Sjoerg copied = 0; 12054Srgrimes encoder_id = (uint32_t *)(uintptr_t)card_res->encoder_id_ptr; 12064Srgrimes#if 1 12075417Sjoerg if (file_priv->master) { 12085417Sjoerg#else 12095417Sjoerg if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 12107090Sbde#endif 12115417Sjoerg list_for_each_entry(encoder, 12124Srgrimes &dev->mode_config.encoder_list, 12134Srgrimes head) { 12145417Sjoerg DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 12155417Sjoerg drm_get_encoder_name(encoder)); 12165417Sjoerg if (copyout(&encoder->base.id, encoder_id + 12175417Sjoerg copied, sizeof(uint32_t))) { 12187393Srgrimes ret = EFAULT; 12195417Sjoerg goto out; 122011162Sjoerg } 122129494Sjoerg copied++; 12225417Sjoerg } 12235417Sjoerg } else { 12245417Sjoerg for (i = mode_group->num_crtcs; 12255417Sjoerg i < mode_group->num_crtcs + mode_group->num_encoders; 122629494Sjoerg i++) { 12275417Sjoerg if (copyout(&mode_group->id_list[i], 12285417Sjoerg encoder_id + copied, sizeof(uint32_t))) { 12295417Sjoerg ret = EFAULT; 12305417Sjoerg goto out; 123129494Sjoerg } 12325417Sjoerg copied++; 12335417Sjoerg } 12345417Sjoerg 12355417Sjoerg } 12365417Sjoerg } 12375417Sjoerg card_res->count_encoders = encoder_count; 1238285Srgrimes 12394Srgrimes /* Connectors */ 1240285Srgrimes if (card_res->count_connectors >= connector_count) { 1241285Srgrimes copied = 0; 12422838Sdg connector_id = (uint32_t *)(uintptr_t)card_res->connector_id_ptr; 12437393Srgrimes#if 1 1244285Srgrimes if (file_priv->master) { 1245285Srgrimes#else 1246285Srgrimes if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { 12472838Sdg#endif 124811162Sjoerg list_for_each_entry(connector, 124911162Sjoerg &dev->mode_config.connector_list, 1250285Srgrimes head) { 1251285Srgrimes DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 12522838Sdg connector->base.id, 12532838Sdg drm_get_connector_name(connector)); 12544Srgrimes if (copyout(&connector->base.id, 12554Srgrimes connector_id + copied, sizeof(uint32_t))) { 12564Srgrimes ret = EFAULT; 12574Srgrimes goto out; 12584Srgrimes } 12594Srgrimes copied++; 1260798Swollman } 12616724Sbde } else { 12624Srgrimes int start = mode_group->num_crtcs + 12634Srgrimes mode_group->num_encoders; 1264851Sache for (i = start; i < start + mode_group->num_connectors; i++) { 12651110Salm if (copyout(&mode_group->id_list[i], 12664Srgrimes connector_id + copied, sizeof(uint32_t))) { 12671110Salm ret = EFAULT; 12681110Salm goto out; 12691110Salm } 12701110Salm copied++; 12711110Salm } 12724Srgrimes } 12738876Srgrimes } 12741110Salm card_res->count_connectors = connector_count; 12751110Salm 12761110Salm DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 12771110Salm card_res->count_connectors, card_res->count_encoders); 12781110Salm 12791110Salmout: 1280863Sache sx_xunlock(&dev->mode_config.mutex); 1281863Sache return ret; 1282863Sache} 128335319Sjulian 128435319Sjulian/** 128535319Sjulian * drm_mode_getcrtc - get CRTC configuration 128635319Sjulian * @inode: inode from the ioctl 1287863Sache * @filp: file * from the ioctl 1288863Sache * @cmd: cmd from ioctl 1289863Sache * @arg: arg from ioctl 1290863Sache * 1291874Sache * LOCKING: 1292878Sache * Takes mode config lock. 1293878Sache * 1294878Sache * Construct a CRTC configuration structure to return to the user. 1295874Sache * 1296874Sache * Called by the user via ioctl. 1297863Sache * 1298878Sache * RETURNS: 1299878Sache * Zero on success, errno on failure. 1300878Sache */ 1301878Sacheint drm_mode_getcrtc(struct drm_device *dev, 1302878Sache void *data, struct drm_file *file_priv) 1303878Sache{ 1304878Sache struct drm_mode_crtc *crtc_resp = data; 1305878Sache struct drm_crtc *crtc; 1306878Sache struct drm_mode_object *obj; 1307878Sache int ret = 0; 1308878Sache 1309878Sache if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1310878Sache return (EINVAL); 1311878Sache 1312878Sache sx_xlock(&dev->mode_config.mutex); 1313878Sache 1314878Sache obj = drm_mode_object_find(dev, crtc_resp->crtc_id, 1315878Sache DRM_MODE_OBJECT_CRTC); 1316878Sache if (!obj) { 1317878Sache ret = (EINVAL); 1318863Sache goto out; 1319878Sache } 1320863Sache crtc = obj_to_crtc(obj); 1321863Sache 1322878Sache crtc_resp->x = crtc->x; 1323878Sache crtc_resp->y = crtc->y; 1324878Sache crtc_resp->gamma_size = crtc->gamma_size; 1325878Sache if (crtc->fb) 1326878Sache crtc_resp->fb_id = crtc->fb->base.id; 1327878Sache else 1328878Sache crtc_resp->fb_id = 0; 1329863Sache 1330863Sache if (crtc->enabled) { 1331863Sache 1332863Sache drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1333855Sache crtc_resp->mode_valid = 1; 13341110Salm 13354Srgrimes } else { 13364Srgrimes crtc_resp->mode_valid = 0; 13374Srgrimes } 13384Srgrimes 13394Srgrimesout: 1340798Swollman sx_xunlock(&dev->mode_config.mutex); 13416724Sbde return ret; 13424Srgrimes} 13434Srgrimes 13442838Sdg/** 13452838Sdg * drm_mode_getconnector - get connector configuration 13461110Salm * @inode: inode from the ioctl 13471110Salm * @filp: file * from the ioctl 13481110Salm * @cmd: cmd from ioctl 13492838Sdg * @arg: arg from ioctl 13501110Salm * 13514Srgrimes * LOCKING: 13522838Sdg * Takes mode config lock. 13535512Sjoerg * 13544Srgrimes * Construct a connector configuration structure to return to the user. 13554Srgrimes * 13564Srgrimes * Called by the user via ioctl. 135737389Sjulian * 135837389Sjulian * RETURNS: 135937389Sjulian * Zero on success, errno on failure. 136037389Sjulian */ 136137389Sjulianint drm_mode_getconnector(struct drm_device *dev, void *data, 13624Srgrimes struct drm_file *file_priv) 136337389Sjulian{ 136437389Sjulian struct drm_mode_get_connector *out_resp = data; 136537389Sjulian struct drm_mode_object *obj; 136637389Sjulian struct drm_connector *connector; 136737389Sjulian struct drm_display_mode *mode; 136837389Sjulian int mode_count = 0; 136937389Sjulian int props_count = 0; 13702838Sdg int encoders_count = 0; 13712838Sdg int ret = 0; 13722838Sdg int copied = 0; 13732838Sdg int i; 13742838Sdg struct drm_mode_modeinfo u_mode; 13752838Sdg struct drm_mode_modeinfo __user *mode_ptr; 137619341Sjoerg uint32_t *prop_ptr; 13772838Sdg uint64_t *prop_values; 13782838Sdg uint32_t *encoder_ptr; 13792838Sdg 13802838Sdg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 13812838Sdg return (EINVAL); 13822838Sdg 13832838Sdg memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 13842838Sdg 13852838Sdg DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 13862838Sdg 13872838Sdg sx_xlock(&dev->mode_config.mutex); 138841693Simp 138941693Simp obj = drm_mode_object_find(dev, out_resp->connector_id, 139041693Simp DRM_MODE_OBJECT_CONNECTOR); 139141693Simp if (!obj) { 139241693Simp ret = EINVAL; 139341693Simp goto out; 139441693Simp } 139541693Simp connector = obj_to_connector(obj); 139641693Simp 139741693Simp for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 139841693Simp if (connector->property_ids[i] != 0) { 13992838Sdg props_count++; 14002838Sdg } 14012838Sdg } 14022838Sdg 14039202Srgrimes for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 14042838Sdg if (connector->encoder_ids[i] != 0) { 14052838Sdg encoders_count++; 14062838Sdg } 14072838Sdg } 14082838Sdg 14092838Sdg if (out_resp->count_modes == 0) { 14102838Sdg connector->funcs->fill_modes(connector, 14118876Srgrimes dev->mode_config.max_width, 14122838Sdg dev->mode_config.max_height); 14132838Sdg } 14149202Srgrimes 14152838Sdg /* delayed so we get modes regardless of pre-fill_modes state */ 14162838Sdg list_for_each_entry(mode, &connector->modes, head) 14175417Sjoerg mode_count++; 14187393Srgrimes 14193490Sphk out_resp->connector_id = connector->base.id; 14202838Sdg out_resp->connector_type = connector->connector_type; 14212838Sdg out_resp->connector_type_id = connector->connector_type_id; 14222838Sdg out_resp->mm_width = connector->display_info.width_mm; 14232838Sdg out_resp->mm_height = connector->display_info.height_mm; 14242838Sdg out_resp->subpixel = connector->display_info.subpixel_order; 14252838Sdg out_resp->connection = connector->status; 14262838Sdg if (connector->encoder) 14272838Sdg out_resp->encoder_id = connector->encoder->base.id; 14282838Sdg else 14292838Sdg out_resp->encoder_id = 0; 14308876Srgrimes 14312838Sdg /* 14322838Sdg * This ioctl is called twice, once to determine how much space is 14332838Sdg * needed, and the 2nd time to fill it. 143419341Sjoerg */ 143519341Sjoerg if ((out_resp->count_modes >= mode_count) && mode_count) { 143619341Sjoerg copied = 0; 143719341Sjoerg mode_ptr = (struct drm_mode_modeinfo *)(uintptr_t)out_resp->modes_ptr; 143819341Sjoerg list_for_each_entry(mode, &connector->modes, head) { 143919341Sjoerg drm_crtc_convert_to_umode(&u_mode, mode); 144019341Sjoerg if (copyout(&u_mode, mode_ptr + copied, 144119341Sjoerg sizeof(u_mode))) { 144219341Sjoerg ret = EFAULT; 144319341Sjoerg goto out; 14442838Sdg } 144519341Sjoerg copied++; 14462838Sdg } 144719341Sjoerg } 144819341Sjoerg out_resp->count_modes = mode_count; 144919341Sjoerg 145019341Sjoerg if ((out_resp->count_props >= props_count) && props_count) { 145119341Sjoerg copied = 0; 14522838Sdg prop_ptr = (uint32_t *)(uintptr_t)(out_resp->props_ptr); 145319341Sjoerg prop_values = (uint64_t *)(uintptr_t)(out_resp->prop_values_ptr); 14542838Sdg for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 145519341Sjoerg if (connector->property_ids[i] != 0) { 14562838Sdg if (copyout(&connector->property_ids[i], 14572838Sdg prop_ptr + copied, sizeof(uint32_t))) { 145812359Sbde ret = EFAULT; 14592838Sdg goto out; 146029677Sgibbs } 146129677Sgibbs 146239228Sgibbs if (copyout(&connector->property_values[i], 146339228Sgibbs prop_values + copied, sizeof(uint64_t))) { 146439228Sgibbs ret = EFAULT; 146539228Sgibbs goto out; 14662838Sdg } 14672838Sdg copied++; 14682838Sdg } 14692838Sdg } 14702838Sdg } 14712838Sdg out_resp->count_props = props_count; 14722838Sdg 14732838Sdg if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 14744Srgrimes copied = 0; 14754Srgrimes encoder_ptr = (uint32_t *)(uintptr_t)(out_resp->encoders_ptr); 14764Srgrimes for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 14774Srgrimes if (connector->encoder_ids[i] != 0) { 14784Srgrimes if (copyout(&connector->encoder_ids[i], 14794Srgrimes encoder_ptr + copied, sizeof(uint32_t))) { 14804Srgrimes ret = EFAULT; 14814Srgrimes goto out; 14824Srgrimes } 1483798Swollman copied++; 14845417Sjoerg } 14854Srgrimes } 14864Srgrimes } 14874Srgrimes out_resp->count_encoders = encoders_count; 14884Srgrimes 14894Srgrimesout: 14904Srgrimes sx_xunlock(&dev->mode_config.mutex); 14914Srgrimes return ret; 14924Srgrimes} 14934Srgrimes 14944Srgrimesint drm_mode_getencoder(struct drm_device *dev, void *data, 14954Srgrimes struct drm_file *file_priv) 1496798Swollman{ 149737945Sbde struct drm_mode_get_encoder *enc_resp = data; 14984Srgrimes struct drm_mode_object *obj; 149937945Sbde struct drm_encoder *encoder; 150037945Sbde int ret = 0; 15012838Sdg 15024Srgrimes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 150337945Sbde return (EINVAL); 150437945Sbde 150537945Sbde sx_xlock(&dev->mode_config.mutex); 15064Srgrimes obj = drm_mode_object_find(dev, enc_resp->encoder_id, 15072838Sdg DRM_MODE_OBJECT_ENCODER); 15082838Sdg if (!obj) { 15092838Sdg ret = EINVAL; 15102838Sdg goto out; 15112838Sdg } 15122838Sdg encoder = obj_to_encoder(obj); 151337945Sbde 151437945Sbde if (encoder->crtc) 151537945Sbde enc_resp->crtc_id = encoder->crtc->base.id; 151637945Sbde else 15172838Sdg enc_resp->crtc_id = 0; 15182838Sdg enc_resp->encoder_type = encoder->encoder_type; 151937945Sbde enc_resp->encoder_id = encoder->base.id; 152037945Sbde enc_resp->possible_crtcs = encoder->possible_crtcs; 152137945Sbde enc_resp->possible_clones = encoder->possible_clones; 1522464Sjkh 1523464Sjkhout: 15244Srgrimes sx_xunlock(&dev->mode_config.mutex); 15254Srgrimes return ret; 15264Srgrimes} 1527798Swollman 15282234Spaul/** 15294Srgrimes * drm_mode_getplane_res - get plane info 1530798Swollman * @dev: DRM device 15314Srgrimes * @data: ioctl data 15322838Sdg * @file_priv: DRM file info 15334Srgrimes * 15344Srgrimes * LOCKING: 15354Srgrimes * Takes mode config lock. 15364Srgrimes * 15374Srgrimes * Return an plane count and set of IDs. 15384Srgrimes */ 15394Srgrimesint drm_mode_getplane_res(struct drm_device *dev, void *data, 15404Srgrimes struct drm_file *file_priv) 15414Srgrimes{ 15424Srgrimes struct drm_mode_get_plane_res *plane_resp = data; 154340565Sbde struct drm_mode_config *config; 1544798Swollman struct drm_plane *plane; 15454Srgrimes uint32_t *plane_ptr; 15464Srgrimes int copied = 0, ret = 0; 15471110Salm 15481110Salm if (!drm_core_check_feature(dev, DRIVER_MODESET)) 15491110Salm return (EINVAL); 15501110Salm 15511110Salm sx_xlock(&dev->mode_config.mutex); 15521110Salm config = &dev->mode_config; 15531110Salm 15542838Sdg /* 15552838Sdg * This ioctl is called twice, once to determine how much space is 15564Srgrimes * needed, and the 2nd time to fill it. 15574Srgrimes */ 155841693Simp if (config->num_plane && 155941693Simp (plane_resp->count_planes >= config->num_plane)) { 156041693Simp plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; 156141693Simp 156241693Simp list_for_each_entry(plane, &config->plane_list, head) { 156341693Simp if (copyout(&plane->base.id, plane_ptr + copied, 156441693Simp sizeof(uint32_t))) { 156541693Simp ret = EFAULT; 156641693Simp goto out; 156741693Simp } 156841693Simp copied++; 156941693Simp } 157041693Simp } 157141693Simp plane_resp->count_planes = config->num_plane; 157241693Simp 157341693Simpout: 157441693Simp sx_xunlock(&dev->mode_config.mutex); 157541693Simp return ret; 157641693Simp} 157741693Simp 157841693Simp/** 157941693Simp * drm_mode_getplane - get plane info 158041693Simp * @dev: DRM device 158141693Simp * @data: ioctl data 158241693Simp * @file_priv: DRM file info 158341693Simp * 158441693Simp * LOCKING: 158541693Simp * Takes mode config lock. 158641693Simp * 158741693Simp * Return plane info, including formats supported, gamma size, any 158841693Simp * current fb, etc. 158941693Simp */ 15904Srgrimesint drm_mode_getplane(struct drm_device *dev, void *data, 15914Srgrimes struct drm_file *file_priv) 15924Srgrimes{ 15934Srgrimes struct drm_mode_get_plane *plane_resp = data; 15942838Sdg struct drm_mode_object *obj; 15955417Sjoerg struct drm_plane *plane; 15964Srgrimes uint32_t *format_ptr; 159737945Sbde int ret = 0; 159819341Sjoerg 15994Srgrimes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 16004Srgrimes return (EINVAL); 160115574Sphk 1602878Sache sx_xlock(&dev->mode_config.mutex); 16032838Sdg obj = drm_mode_object_find(dev, plane_resp->plane_id, 16044Srgrimes DRM_MODE_OBJECT_PLANE); 160529677Sgibbs if (!obj) { 160615574Sphk ret = ENOENT; 16074Srgrimes goto out; 16084Srgrimes } 16094Srgrimes plane = obj_to_plane(obj); 16104Srgrimes 16114Srgrimes if (plane->crtc) 16124Srgrimes plane_resp->crtc_id = plane->crtc->base.id; 16134Srgrimes else 16147393Srgrimes plane_resp->crtc_id = 0; 16152838Sdg 16164Srgrimes if (plane->fb) 16174Srgrimes plane_resp->fb_id = plane->fb->base.id; 16184Srgrimes else 16192838Sdg plane_resp->fb_id = 0; 16204Srgrimes 16214Srgrimes plane_resp->plane_id = plane->base.id; 16224Srgrimes plane_resp->possible_crtcs = plane->possible_crtcs; 16234Srgrimes plane_resp->gamma_size = plane->gamma_size; 16242838Sdg 16254Srgrimes /* 16264Srgrimes * This ioctl is called twice, once to determine how much space is 16277393Srgrimes * needed, and the 2nd time to fill it. 16284Srgrimes */ 16294Srgrimes if (plane->format_count && 1630878Sache (plane_resp->count_format_types >= plane->format_count)) { 163119341Sjoerg format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; 163231493Sphk if (copyout(format_ptr, 163319341Sjoerg plane->format_types, 163419341Sjoerg sizeof(uint32_t) * plane->format_count)) { 163519341Sjoerg ret = EFAULT; 163619341Sjoerg goto out; 163735319Sjulian } 163819341Sjoerg } 163919341Sjoerg plane_resp->count_format_types = plane->format_count; 164019341Sjoerg 16412838Sdgout: 16422838Sdg sx_xunlock(&dev->mode_config.mutex); 16432838Sdg return ret; 164429677Sgibbs} 164529752Sgibbs 16464Srgrimes/** 16474Srgrimes * drm_mode_setplane - set up or tear down an plane 16484Srgrimes * @dev: DRM device 16494Srgrimes * @data: ioctl data* 16504Srgrimes * @file_prive: DRM file info 16514Srgrimes * 16524Srgrimes * LOCKING: 16534Srgrimes * Takes mode config lock. 16542838Sdg * 16552838Sdg * Set plane info, including placement, fb, scaling, and other factors. 16564Srgrimes * Or pass a NULL fb to disable. 16574Srgrimes */ 165835256Sdesint drm_mode_setplane(struct drm_device *dev, void *data, 16594Srgrimes struct drm_file *file_priv) 16604Srgrimes{ 16614Srgrimes struct drm_mode_set_plane *plane_req = data; 16624Srgrimes struct drm_mode_object *obj; 16634Srgrimes struct drm_plane *plane; 16644Srgrimes struct drm_crtc *crtc; 16654Srgrimes struct drm_framebuffer *fb; 16664Srgrimes int ret = 0; 16674Srgrimes unsigned int fb_width, fb_height; 16684Srgrimes int i; 16694Srgrimes 16704Srgrimes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 16714Srgrimes return (EINVAL); 16724Srgrimes 16734Srgrimes sx_xlock(&dev->mode_config.mutex); 16744Srgrimes 16754Srgrimes /* 16762838Sdg * First, find the plane, crtc, and fb objects. If not available, 16774Srgrimes * we don't bother to call the driver. 167837945Sbde */ 167937945Sbde obj = drm_mode_object_find(dev, plane_req->plane_id, 168037945Sbde DRM_MODE_OBJECT_PLANE); 168137945Sbde if (!obj) { 168237945Sbde DRM_DEBUG_KMS("Unknown plane ID %d\n", 16834Srgrimes plane_req->plane_id); 16844Srgrimes ret = ENOENT; 168519341Sjoerg goto out; 16864Srgrimes } 16874Srgrimes plane = obj_to_plane(obj); 16884Srgrimes 16894Srgrimes /* No fb means shut it down */ 16905417Sjoerg if (!plane_req->fb_id) { 169119341Sjoerg plane->funcs->disable_plane(plane); 16925417Sjoerg plane->crtc = NULL; 16933755Sjoerg plane->fb = NULL; 16943755Sjoerg goto out; 16953755Sjoerg } 16963755Sjoerg 16973755Sjoerg obj = drm_mode_object_find(dev, plane_req->crtc_id, 16983755Sjoerg DRM_MODE_OBJECT_CRTC); 16993755Sjoerg if (!obj) { 17003755Sjoerg DRM_DEBUG_KMS("Unknown crtc ID %d\n", 17015417Sjoerg plane_req->crtc_id); 17024Srgrimes ret = ENOENT; 17034Srgrimes goto out; 17044Srgrimes } 17054Srgrimes crtc = obj_to_crtc(obj); 17064618Sphk 17074Srgrimes obj = drm_mode_object_find(dev, plane_req->fb_id, 17084Srgrimes DRM_MODE_OBJECT_FB); 17094Srgrimes if (!obj) { 17104Srgrimes DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 17115417Sjoerg plane_req->fb_id); 17124Srgrimes ret = ENOENT; 171319341Sjoerg goto out; 17142838Sdg } 17152838Sdg fb = obj_to_fb(obj); 17165417Sjoerg 17175417Sjoerg /* Check whether this plane supports the fb pixel format. */ 17185417Sjoerg for (i = 0; i < plane->format_count; i++) 17195417Sjoerg if (fb->pixel_format == plane->format_types[i]) 17205417Sjoerg break; 17215417Sjoerg if (i == plane->format_count) { 17225417Sjoerg DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); 17235417Sjoerg ret = EINVAL; 17245417Sjoerg goto out; 17255417Sjoerg } 17265417Sjoerg 17275417Sjoerg fb_width = fb->width << 16; 17285417Sjoerg fb_height = fb->height << 16; 17295417Sjoerg 17305417Sjoerg /* Make sure source coordinates are inside the fb. */ 17315417Sjoerg if (plane_req->src_w > fb_width || 17325417Sjoerg plane_req->src_x > fb_width - plane_req->src_w || 17335417Sjoerg plane_req->src_h > fb_height || 17345417Sjoerg plane_req->src_y > fb_height - plane_req->src_h) { 17352838Sdg DRM_DEBUG_KMS("Invalid source coordinates " 17365417Sjoerg "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 17375417Sjoerg plane_req->src_w >> 16, 17385417Sjoerg ((plane_req->src_w & 0xffff) * 15625) >> 10, 17395417Sjoerg plane_req->src_h >> 16, 17405417Sjoerg ((plane_req->src_h & 0xffff) * 15625) >> 10, 17415417Sjoerg plane_req->src_x >> 16, 17422838Sdg ((plane_req->src_x & 0xffff) * 15625) >> 10, 17435417Sjoerg plane_req->src_y >> 16, 17442838Sdg ((plane_req->src_y & 0xffff) * 15625) >> 10); 17452838Sdg ret = ENOSPC; 17465417Sjoerg goto out; 17472838Sdg } 17482838Sdg 17492838Sdg /* Give drivers some help against integer overflows */ 17502838Sdg if (plane_req->crtc_w > INT_MAX || 17515417Sjoerg plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 17525417Sjoerg plane_req->crtc_h > INT_MAX || 17532838Sdg plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 17542838Sdg DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 17552838Sdg plane_req->crtc_w, plane_req->crtc_h, 17562838Sdg plane_req->crtc_x, plane_req->crtc_y); 17575417Sjoerg ret = ERANGE; 17585417Sjoerg goto out; 17595417Sjoerg } 17605417Sjoerg 17615417Sjoerg ret = -plane->funcs->update_plane(plane, crtc, fb, 17622838Sdg plane_req->crtc_x, plane_req->crtc_y, 17632838Sdg plane_req->crtc_w, plane_req->crtc_h, 17642838Sdg plane_req->src_x, plane_req->src_y, 17652838Sdg plane_req->src_w, plane_req->src_h); 17662838Sdg if (!ret) { 17675417Sjoerg plane->crtc = crtc; 17684Srgrimes plane->fb = fb; 17694Srgrimes } 17702838Sdg 17712838Sdgout: 17728376Srgrimes sx_xunlock(&dev->mode_config.mutex); 177337733Sbde 177437733Sbde return ret; 17754Srgrimes} 17764Srgrimes 17774Srgrimes/** 17784Srgrimes * drm_mode_setcrtc - set CRTC configuration 177919341Sjoerg * @inode: inode from the ioctl 178041693Simp * @filp: file * from the ioctl 178141693Simp * @cmd: cmd from ioctl 178241693Simp * @arg: arg from ioctl 178341693Simp * 178441693Simp * LOCKING: 17854Srgrimes * Takes mode config lock. 17864Srgrimes * 17874Srgrimes * Build a new CRTC configuration based on user request. 17884Srgrimes * 17892838Sdg * Called by the user via ioctl. 17904Srgrimes * 17912838Sdg * RETURNS: 17922838Sdg * Zero on success, errno on failure. 17932838Sdg */ 17945417Sjoergint drm_mode_setcrtc(struct drm_device *dev, void *data, 17953755Sjoerg struct drm_file *file_priv) 17963755Sjoerg{ 179737945Sbde struct drm_mode_config *config = &dev->mode_config; 179837945Sbde struct drm_mode_crtc *crtc_req = data; 179937945Sbde struct drm_mode_object *obj; 18003755Sjoerg struct drm_crtc *crtc; 18013755Sjoerg struct drm_connector **connector_set = NULL, *connector; 18023755Sjoerg struct drm_framebuffer *fb = NULL; 18032838Sdg struct drm_display_mode *mode = NULL; 18042838Sdg struct drm_mode_set set; 18052838Sdg uint32_t *set_connectors_ptr; 18062838Sdg int ret = 0; 18072838Sdg int i; 18082838Sdg 18092838Sdg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 18102838Sdg return (EINVAL); 18112838Sdg 18122838Sdg /* For some reason crtc x/y offsets are signed internally. */ 18132838Sdg if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 18142838Sdg return (ERANGE); 18152838Sdg 18162838Sdg sx_xlock(&dev->mode_config.mutex); 18172838Sdg obj = drm_mode_object_find(dev, crtc_req->crtc_id, 18182838Sdg DRM_MODE_OBJECT_CRTC); 18192838Sdg if (!obj) { 18202838Sdg DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 18212838Sdg ret = EINVAL; 18222838Sdg goto out; 18232838Sdg } 1824878Sache crtc = obj_to_crtc(obj); 18254Srgrimes DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 182641693Simp 182741693Simp if (crtc_req->mode_valid) { 182841693Simp /* If we have a mode we need a framebuffer. */ 182941693Simp /* If we pass -1, set the mode with the currently bound fb */ 183041693Simp if (crtc_req->fb_id == -1) { 183141693Simp if (!crtc->fb) { 1832878Sache DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 18338876Srgrimes ret = -EINVAL; 18345417Sjoerg goto out; 18355417Sjoerg } 18365417Sjoerg fb = crtc->fb; 18375417Sjoerg } else { 18385417Sjoerg obj = drm_mode_object_find(dev, crtc_req->fb_id, 18395417Sjoerg DRM_MODE_OBJECT_FB); 18405417Sjoerg if (!obj) { 18413755Sjoerg DRM_DEBUG_KMS("Unknown FB ID%d\n", 18423755Sjoerg crtc_req->fb_id); 184337945Sbde ret = EINVAL; 184437945Sbde goto out; 184537945Sbde } 18463755Sjoerg fb = obj_to_fb(obj); 18473755Sjoerg } 18483755Sjoerg 18498876Srgrimes mode = drm_mode_create(dev); 18504Srgrimes if (!mode) { 18514Srgrimes ret = ENOMEM; 185241693Simp goto out; 185341693Simp } 185441693Simp 185541693Simp ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 185641693Simp if (ret) { 185741693Simp DRM_DEBUG_KMS("Invalid mode\n"); 185841693Simp goto out; 185941693Simp } 186041693Simp 186141693Simp drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 186241693Simp 186341693Simp if (mode->hdisplay > fb->width || 186441693Simp mode->vdisplay > fb->height || 186541693Simp crtc_req->x > fb->width - mode->hdisplay || 186641693Simp crtc_req->y > fb->height - mode->vdisplay) { 186741693Simp DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n", 186841693Simp mode->hdisplay, mode->vdisplay, 186941693Simp crtc_req->x, crtc_req->y, 18705417Sjoerg fb->width, fb->height); 18715417Sjoerg ret = ENOSPC; 18725417Sjoerg goto out; 18735417Sjoerg } 18745417Sjoerg } 18755417Sjoerg 18765417Sjoerg if (crtc_req->count_connectors == 0 && mode) { 18775417Sjoerg DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 18785417Sjoerg ret = EINVAL; 18795417Sjoerg goto out; 18805417Sjoerg } 1881878Sache 18823755Sjoerg if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 188337945Sbde DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 188437945Sbde crtc_req->count_connectors); 188537945Sbde ret = EINVAL; 18863755Sjoerg goto out; 18873755Sjoerg } 1888878Sache 1889878Sache if (crtc_req->count_connectors > 0) { 189041693Simp u32 out_id; 189141693Simp 189241693Simp /* Avoid unbounded kernel memory allocation */ 189341693Simp if (crtc_req->count_connectors > config->num_connector) { 189441693Simp ret = EINVAL; 189541693Simp goto out; 189641693Simp } 189741693Simp 189841693Simp connector_set = malloc(crtc_req->count_connectors * 189941693Simp sizeof(struct drm_connector *), DRM_MEM_KMS, M_WAITOK); 190041693Simp 190141693Simp for (i = 0; i < crtc_req->count_connectors; i++) { 190241693Simp set_connectors_ptr = (uint32_t *)(uintptr_t)crtc_req->set_connectors_ptr; 190341693Simp if (copyin(&set_connectors_ptr[i], &out_id, sizeof(uint32_t))) { 190441693Simp ret = EFAULT; 190541693Simp goto out; 190641693Simp } 190741693Simp 19084Srgrimes obj = drm_mode_object_find(dev, out_id, 190937945Sbde DRM_MODE_OBJECT_CONNECTOR); 19104Srgrimes if (!obj) { 191141693Simp DRM_DEBUG_KMS("Connector id %d unknown\n", 191241693Simp out_id); 191341693Simp ret = EINVAL; 191441693Simp goto out; 191541693Simp } 191641693Simp connector = obj_to_connector(obj); 191741693Simp DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 191841693Simp connector->base.id, 191941693Simp drm_get_connector_name(connector)); 192041693Simp 19214Srgrimes connector_set[i] = connector; 192237945Sbde } 19235417Sjoerg } 19245417Sjoerg 19254Srgrimes set.crtc = crtc; 192637945Sbde set.x = crtc_req->x; 192737945Sbde set.y = crtc_req->y; 192837945Sbde set.mode = mode; 19295417Sjoerg set.connectors = connector_set; 19305417Sjoerg set.num_connectors = crtc_req->count_connectors; 19315417Sjoerg set.fb = fb; 19325417Sjoerg ret = crtc->funcs->set_config(&set); 19335417Sjoerg 19342838Sdgout: 19355417Sjoerg free(connector_set, DRM_MEM_KMS); 19362838Sdg drm_mode_destroy(dev, mode); 19375417Sjoerg sx_xunlock(&dev->mode_config.mutex); 19382838Sdg return ret; 193941693Simp} 194041693Simp 194141693Simpint drm_mode_cursor_ioctl(struct drm_device *dev, 194241693Simp void *data, struct drm_file *file_priv) 194341693Simp{ 19442838Sdg struct drm_mode_cursor *req = data; 19454Srgrimes struct drm_mode_object *obj; 19462838Sdg struct drm_crtc *crtc; 19472838Sdg int ret = 0; 1948878Sache 19492838Sdg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 19502838Sdg return (EINVAL); 19512838Sdg 19522838Sdg if (!req->flags) 19532838Sdg return (EINVAL); 1954878Sache 1955878Sache sx_xlock(&dev->mode_config.mutex); 1956878Sache obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); 1957878Sache if (!obj) { 19582838Sdg DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 19592838Sdg ret = EINVAL; 19602838Sdg goto out; 19612838Sdg } 19622838Sdg crtc = obj_to_crtc(obj); 19632838Sdg 19642838Sdg if (req->flags & DRM_MODE_CURSOR_BO) { 19654Srgrimes if (!crtc->funcs->cursor_set) { 19664Srgrimes ret = ENXIO; 19674Srgrimes goto out; 19682838Sdg } 196919341Sjoerg /* Turns off the cursor if handle is 0 */ 19704Srgrimes ret = -crtc->funcs->cursor_set(crtc, file_priv, req->handle, 19714Srgrimes req->width, req->height); 19724Srgrimes } 19734Srgrimes 19744Srgrimes if (req->flags & DRM_MODE_CURSOR_MOVE) { 19754Srgrimes if (crtc->funcs->cursor_move) { 19764Srgrimes ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 19774Srgrimes } else { 197829677Sgibbs ret = EFAULT; 197939228Sgibbs goto out; 198039228Sgibbs } 198139228Sgibbs } 198239228Sgibbsout: 198339228Sgibbs sx_xunlock(&dev->mode_config.mutex); 198439228Sgibbs return ret; 19854Srgrimes} 19864Srgrimes 19874Srgrimes/* Original addfb only supported RGB formats, so figure out which one */ 19884Srgrimesuint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 19894Srgrimes{ 19904Srgrimes uint32_t fmt; 19914Srgrimes 19922838Sdg switch (bpp) { 19934Srgrimes case 8: 199437945Sbde fmt = DRM_FORMAT_RGB332; 199537945Sbde break; 199637945Sbde case 16: 199737945Sbde if (depth == 15) 199837945Sbde fmt = DRM_FORMAT_XRGB1555; 199937945Sbde else 200037945Sbde fmt = DRM_FORMAT_RGB565; 200137945Sbde break; 200237945Sbde case 24: 20034Srgrimes fmt = DRM_FORMAT_RGB888; 200437945Sbde break; 20054Srgrimes case 32: 20065417Sjoerg if (depth == 24) 20075417Sjoerg fmt = DRM_FORMAT_XRGB8888; 20085417Sjoerg else if (depth == 30) 20093755Sjoerg fmt = DRM_FORMAT_XRGB2101010; 20103755Sjoerg else 20113755Sjoerg fmt = DRM_FORMAT_ARGB8888; 20123755Sjoerg break; 20133755Sjoerg default: 20144Srgrimes DRM_ERROR("bad bpp, assuming RGB24 pixel format\n"); 20154Srgrimes fmt = DRM_FORMAT_XRGB8888; 20164Srgrimes break; 20174Srgrimes } 20184618Sphk 20194Srgrimes return fmt; 20204Srgrimes} 20214Srgrimes 20222838Sdg/** 20232838Sdg * drm_mode_addfb - add an FB to the graphics configuration 20245417Sjoerg * @inode: inode from the ioctl 20252838Sdg * @filp: file * from the ioctl 20265417Sjoerg * @cmd: cmd from ioctl 20275417Sjoerg * @arg: arg from ioctl 20285417Sjoerg * 20295417Sjoerg * LOCKING: 20305417Sjoerg * Takes mode config lock. 20312838Sdg * 20322838Sdg * Add a new FB to the specified CRTC, given a user request. 20334Srgrimes * 20343755Sjoerg * Called by the user via ioctl. 20353755Sjoerg * 20363755Sjoerg * RETURNS: 20373755Sjoerg * Zero on success, errno on failure. 20383755Sjoerg */ 20393755Sjoergint drm_mode_addfb(struct drm_device *dev, 20403755Sjoerg void *data, struct drm_file *file_priv) 20413755Sjoerg{ 20423755Sjoerg struct drm_mode_fb_cmd *or = data; 20433755Sjoerg struct drm_mode_fb_cmd2 r = {}; 20443755Sjoerg struct drm_mode_config *config = &dev->mode_config; 20452838Sdg struct drm_framebuffer *fb; 20464Srgrimes int ret = 0; 20474Srgrimes 20484Srgrimes /* Use new struct with format internally */ 20494Srgrimes r.fb_id = or->fb_id; 20504Srgrimes r.width = or->width; 20514Srgrimes r.height = or->height; 20522838Sdg r.pitches[0] = or->pitch; 20534Srgrimes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 20544Srgrimes r.handles[0] = or->handle; 20554Srgrimes 20564Srgrimes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 205737945Sbde return (EINVAL); 205837945Sbde 205937945Sbde if ((config->min_width > r.width) || (r.width > config->max_width)) 206037945Sbde return (EINVAL); 206137945Sbde if ((config->min_height > r.height) || (r.height > config->max_height)) 206237945Sbde return (EINVAL); 206337945Sbde 206437945Sbde sx_xlock(&dev->mode_config.mutex); 206537945Sbde 206637945Sbde ret = -dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb); 206737945Sbde if (ret != 0) { 20684Srgrimes DRM_ERROR("could not create framebuffer, error %d\n", ret); 20694Srgrimes goto out; 20705417Sjoerg } 20715417Sjoerg 207237554Sbde or->fb_id = fb->base.id; 20732838Sdg list_add(&fb->filp_head, &file_priv->fbs); 20742838Sdg DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 20752838Sdg 20762838Sdgout: 20772838Sdg sx_xunlock(&dev->mode_config.mutex); 20782838Sdg return ret; 20792838Sdg} 20802838Sdg 20815552Sjoergstatic int format_check(struct drm_mode_fb_cmd2 *r) 20825552Sjoerg{ 20835552Sjoerg uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 20845552Sjoerg 20855552Sjoerg switch (format) { 20865552Sjoerg case DRM_FORMAT_C8: 20875552Sjoerg case DRM_FORMAT_RGB332: 20884Srgrimes case DRM_FORMAT_BGR233: 20894Srgrimes case DRM_FORMAT_XRGB4444: 20905552Sjoerg case DRM_FORMAT_XBGR4444: 20914Srgrimes case DRM_FORMAT_RGBX4444: 20924Srgrimes case DRM_FORMAT_BGRX4444: 20934Srgrimes case DRM_FORMAT_ARGB4444: 2094879Swollman case DRM_FORMAT_ABGR4444: 2095464Sjkh case DRM_FORMAT_RGBA4444: 2096464Sjkh case DRM_FORMAT_BGRA4444: 20974Srgrimes case DRM_FORMAT_XRGB1555: 20984Srgrimes case DRM_FORMAT_XBGR1555: 209915574Sphk case DRM_FORMAT_RGBX5551: 21004Srgrimes case DRM_FORMAT_BGRX5551: 210129677Sgibbs case DRM_FORMAT_ARGB1555: 21024Srgrimes case DRM_FORMAT_ABGR1555: 21032838Sdg case DRM_FORMAT_RGBA5551: 21042838Sdg case DRM_FORMAT_BGRA5551: 21054Srgrimes case DRM_FORMAT_RGB565: 21064Srgrimes case DRM_FORMAT_BGR565: 21074Srgrimes case DRM_FORMAT_RGB888: 21084Srgrimes case DRM_FORMAT_BGR888: 21094Srgrimes case DRM_FORMAT_XRGB8888: 21104Srgrimes case DRM_FORMAT_XBGR8888: 21114Srgrimes case DRM_FORMAT_RGBX8888: 21124Srgrimes case DRM_FORMAT_BGRX8888: 21134Srgrimes case DRM_FORMAT_ARGB8888: 21144Srgrimes case DRM_FORMAT_ABGR8888: 21154Srgrimes case DRM_FORMAT_RGBA8888: 21164Srgrimes case DRM_FORMAT_BGRA8888: 21174Srgrimes case DRM_FORMAT_XRGB2101010: 21184Srgrimes case DRM_FORMAT_XBGR2101010: 21192838Sdg case DRM_FORMAT_RGBX1010102: 21204Srgrimes case DRM_FORMAT_BGRX1010102: 2121863Sache case DRM_FORMAT_ARGB2101010: 2122863Sache case DRM_FORMAT_ABGR2101010: 21232838Sdg case DRM_FORMAT_RGBA1010102: 212435319Sjulian case DRM_FORMAT_BGRA1010102: 2125499Srgrimes case DRM_FORMAT_YUYV: 21262838Sdg case DRM_FORMAT_YVYU: 21272838Sdg case DRM_FORMAT_UYVY: 2128863Sache case DRM_FORMAT_VYUY: 21295417Sjoerg case DRM_FORMAT_AYUV: 21305417Sjoerg case DRM_FORMAT_NV12: 21315417Sjoerg case DRM_FORMAT_NV21: 213237554Sbde case DRM_FORMAT_NV16: 21335417Sjoerg case DRM_FORMAT_NV61: 21345417Sjoerg case DRM_FORMAT_YUV410: 21355417Sjoerg case DRM_FORMAT_YVU410: 21365417Sjoerg case DRM_FORMAT_YUV411: 21375417Sjoerg case DRM_FORMAT_YVU411: 21385417Sjoerg case DRM_FORMAT_YUV420: 21395417Sjoerg case DRM_FORMAT_YVU420: 21405417Sjoerg case DRM_FORMAT_YUV422: 21414Srgrimes case DRM_FORMAT_YVU422: 21424Srgrimes case DRM_FORMAT_YUV444: 21434Srgrimes case DRM_FORMAT_YVU444: 214419341Sjoerg return 0; 214529677Sgibbs default: 214639228Sgibbs return (EINVAL); 214739228Sgibbs } 214839312Sgibbs} 214939228Sgibbs 215039228Sgibbs/** 215139228Sgibbs * drm_mode_addfb2 - add an FB to the graphics configuration 215239228Sgibbs * @inode: inode from the ioctl 21534Srgrimes * @filp: file * from the ioctl 21544Srgrimes * @cmd: cmd from ioctl 2155499Srgrimes * @arg: arg from ioctl 215637945Sbde * 21574Srgrimes * LOCKING: 21584Srgrimes * Takes mode config lock. 2159499Srgrimes * 21604Srgrimes * Add a new FB to the specified CRTC, given a user request with format. 21614Srgrimes * 21624Srgrimes * Called by the user via ioctl. 21634Srgrimes * 21644Srgrimes * RETURNS: 2165878Sache * Zero on success, errno on failure. 2166878Sache */ 2167878Sacheint drm_mode_addfb2(struct drm_device *dev, 2168878Sache void *data, struct drm_file *file_priv) 2169878Sache{ 2170878Sache struct drm_mode_fb_cmd2 *r = data; 2171878Sache struct drm_mode_config *config = &dev->mode_config; 2172878Sache struct drm_framebuffer *fb; 2173878Sache int ret = 0; 2174878Sache 2175878Sache if (!drm_core_check_feature(dev, DRIVER_MODESET)) 21762838Sdg return (EINVAL); 21772838Sdg 217835319Sjulian if ((config->min_width > r->width) || (r->width > config->max_width)) { 217935319Sjulian DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", 21802838Sdg r->width, config->min_width, config->max_width); 2181878Sache return (EINVAL); 2182878Sache } 2183878Sache if ((config->min_height > r->height) || (r->height > config->max_height)) { 2184878Sache DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", 2185878Sache r->height, config->min_height, config->max_height); 21867042Sjoerg return (EINVAL); 21877042Sjoerg } 21887042Sjoerg 21897042Sjoerg ret = format_check(r); 2190878Sache if (ret) { 2191878Sache DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format); 2192878Sache return ret; 2193878Sache } 2194878Sache 2195878Sache sx_xlock(&dev->mode_config.mutex); 2196878Sache 2197878Sache /* TODO check buffer is sufficiently large */ 2198878Sache /* TODO setup destructor callback */ 21992838Sdg 2200878Sache ret = -dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb); 2201878Sache if (ret != 0) { 220231493Sphk DRM_ERROR("could not create framebuffer, error %d\n", ret); 22038876Srgrimes goto out; 2204878Sache } 220535319Sjulian 2206878Sache r->fb_id = fb->base.id; 2207878Sache list_add(&fb->filp_head, &file_priv->fbs); 2208878Sache DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 2209878Sache 2210878Sacheout: 2211878Sache sx_xunlock(&dev->mode_config.mutex); 22124088Sjkh return (ret); 2213878Sache} 2214878Sache 2215878Sache/** 2216878Sache * drm_mode_rmfb - remove an FB from the configuration 22178876Srgrimes * @inode: inode from the ioctl 22187042Sjoerg * @filp: file * from the ioctl 2219878Sache * @cmd: cmd from ioctl 2220878Sache * @arg: arg from ioctl 22217042Sjoerg * 22227042Sjoerg * LOCKING: 22232838Sdg * Takes mode config lock. 22242838Sdg * 22257042Sjoerg * Remove the FB specified by the user. 22267042Sjoerg * 22277042Sjoerg * Called by the user via ioctl. 22287042Sjoerg * 2229878Sache * RETURNS: 2230878Sache * Zero on success, errno on failure. 2231878Sache */ 2232878Sacheint drm_mode_rmfb(struct drm_device *dev, 2233464Sjkh void *data, struct drm_file *file_priv) 22346724Sbde{ 2235464Sjkh struct drm_mode_object *obj; 2236464Sjkh struct drm_framebuffer *fb = NULL; 223735319Sjulian struct drm_framebuffer *fbl = NULL; 22382838Sdg uint32_t *id = data; 2239878Sache int ret = 0; 224036735Sdfr int found = 0; 2241878Sache 2242878Sache if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2243878Sache return (EINVAL); 2244464Sjkh 22452838Sdg sx_xlock(&dev->mode_config.mutex); 22462838Sdg obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); 22472838Sdg /* TODO check that we really get a framebuffer back. */ 22482838Sdg if (!obj) { 2249878Sache ret = EINVAL; 2250878Sache goto out; 2251878Sache } 22522838Sdg fb = obj_to_fb(obj); 2253464Sjkh 22541110Salm list_for_each_entry(fbl, &file_priv->fbs, filp_head) 22551161Snate if (fb == fbl) 22561161Snate found = 1; 22571161Snate 22581161Snate if (!found) { 22591110Salm ret = EINVAL; 22601110Salm goto out; 22611110Salm } 22622838Sdg 2263464Sjkh /* TODO release all crtc connected to the framebuffer */ 2264878Sache /* TODO unhock the destructor from the buffer object */ 2265878Sache 2266878Sache list_del(&fb->filp_head); 2267878Sache fb->funcs->destroy(fb); 2268878Sache 22692838Sdgout: 2270878Sache sx_xunlock(&dev->mode_config.mutex); 2271878Sache return ret; 2272878Sache} 2273464Sjkh 227410823Sbde/** 227510823Sbde * drm_mode_getfb - get FB info 2276878Sache * @inode: inode from the ioctl 2277878Sache * @filp: file * from the ioctl 2278878Sache * @cmd: cmd from ioctl 2279464Sjkh * @arg: arg from ioctl 2280878Sache * 2281878Sache * LOCKING: 2282464Sjkh * Takes mode config lock. 2283878Sache * 2284878Sache * Lookup the FB given its ID and return info about it. 2285878Sache * 2286878Sache * Called by the user via ioctl. 2287464Sjkh * 2288878Sache * RETURNS: 2289878Sache * Zero on success, errno on failure. 2290878Sache */ 2291878Sacheint drm_mode_getfb(struct drm_device *dev, 2292464Sjkh void *data, struct drm_file *file_priv) 2293878Sache{ 2294878Sache struct drm_mode_fb_cmd *r = data; 2295878Sache struct drm_mode_object *obj; 2296878Sache struct drm_framebuffer *fb; 2297878Sache int ret = 0; 2298878Sache 2299464Sjkh if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2300878Sache return (EINVAL); 2301464Sjkh 230210823Sbde sx_xlock(&dev->mode_config.mutex); 230310823Sbde obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 2304878Sache if (!obj) { 2305464Sjkh ret = EINVAL; 2306878Sache goto out; 23073940Sjkh } 2308878Sache fb = obj_to_fb(obj); 2309878Sache 2310878Sache r->height = fb->height; 2311878Sache r->width = fb->width; 2312878Sache r->depth = fb->depth; 2313878Sache r->bpp = fb->bits_per_pixel; 2314878Sache r->pitch = fb->pitches[0]; 2315878Sache fb->funcs->create_handle(fb, file_priv, &r->handle); 2316878Sache 2317878Sacheout: 2318464Sjkh sx_xunlock(&dev->mode_config.mutex); 2319878Sache return ret; 232035319Sjulian} 2321878Sache 2322464Sjkhint drm_mode_dirtyfb_ioctl(struct drm_device *dev, 23232838Sdg void *data, struct drm_file *file_priv) 23242838Sdg{ 23252838Sdg struct drm_clip_rect __user *clips_ptr; 23262838Sdg struct drm_clip_rect *clips = NULL; 232735319Sjulian struct drm_mode_fb_dirty_cmd *r = data; 23282838Sdg struct drm_mode_object *obj; 23292838Sdg struct drm_framebuffer *fb; 23302838Sdg unsigned flags; 233135319Sjulian int num_clips; 23322838Sdg int ret = 0; 23338876Srgrimes 23342838Sdg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 233535319Sjulian return (EINVAL); 23362838Sdg 23372838Sdg sx_xlock(&dev->mode_config.mutex); 2338878Sache obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); 23392838Sdg if (!obj) { 2340878Sache ret = EINVAL; 2341878Sache goto out_err1; 2342878Sache } 2343464Sjkh fb = obj_to_fb(obj); 2344464Sjkh 234512502Sjulian num_clips = r->num_clips; 234612502Sjulian clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr; 234712502Sjulian 234812675Sjulian if (!num_clips != !clips_ptr) { 234912502Sjulian ret = EINVAL; 235012675Sjulian goto out_err1; 235112502Sjulian } 235237389Sjulian 235312502Sjulian flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 235412502Sjulian 235512502Sjulian /* If userspace annotates copy, clips must come in pairs */ 235612675Sjulian if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 235712675Sjulian ret = EINVAL; 235812675Sjulian goto out_err1; 235935319Sjulian } 23604Srgrimes 236135319Sjulian if (num_clips && clips_ptr) { 23622838Sdg if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 23632838Sdg ret = EINVAL; 23642838Sdg goto out_err1; 23652838Sdg } 23662838Sdg clips = malloc(num_clips * sizeof(*clips), DRM_MEM_KMS, 23672838Sdg M_WAITOK | M_ZERO); 23682838Sdg 23692838Sdg ret = copyin(clips_ptr, clips, num_clips * sizeof(*clips)); 23702838Sdg if (ret) 23712838Sdg goto out_err2; 23722838Sdg } 23732838Sdg 23742838Sdg if (fb->funcs->dirty) { 23752838Sdg ret = -fb->funcs->dirty(fb, file_priv, flags, r->color, 23762838Sdg clips, num_clips); 23772838Sdg } else { 2378 ret = ENOSYS; 2379 goto out_err2; 2380 } 2381 2382out_err2: 2383 free(clips, DRM_MEM_KMS); 2384out_err1: 2385 sx_xunlock(&dev->mode_config.mutex); 2386 return ret; 2387} 2388 2389 2390/** 2391 * drm_fb_release - remove and free the FBs on this file 2392 * @filp: file * from the ioctl 2393 * 2394 * LOCKING: 2395 * Takes mode config lock. 2396 * 2397 * Destroy all the FBs associated with @filp. 2398 * 2399 * Called by the user via ioctl. 2400 * 2401 * RETURNS: 2402 * Zero on success, errno on failure. 2403 */ 2404void drm_fb_release(struct drm_file *priv) 2405{ 2406#if 1 2407 struct drm_device *dev = priv->dev; 2408#else 2409 struct drm_device *dev = priv->minor->dev; 2410#endif 2411 struct drm_framebuffer *fb, *tfb; 2412 2413 sx_xlock(&dev->mode_config.mutex); 2414 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 2415 list_del(&fb->filp_head); 2416 fb->funcs->destroy(fb); 2417 } 2418 sx_xunlock(&dev->mode_config.mutex); 2419} 2420 2421/** 2422 * drm_mode_attachmode - add a mode to the user mode list 2423 * @dev: DRM device 2424 * @connector: connector to add the mode to 2425 * @mode: mode to add 2426 * 2427 * Add @mode to @connector's user mode list. 2428 */ 2429static void drm_mode_attachmode(struct drm_device *dev, 2430 struct drm_connector *connector, 2431 struct drm_display_mode *mode) 2432{ 2433 list_add_tail(&mode->head, &connector->user_modes); 2434} 2435 2436int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, 2437 const struct drm_display_mode *mode) 2438{ 2439 struct drm_connector *connector; 2440 int ret = 0; 2441 struct drm_display_mode *dup_mode, *next; 2442 DRM_LIST_HEAD(list); 2443 2444 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2445 if (!connector->encoder) 2446 continue; 2447 if (connector->encoder->crtc == crtc) { 2448 dup_mode = drm_mode_duplicate(dev, mode); 2449 if (!dup_mode) { 2450 ret = ENOMEM; 2451 goto out; 2452 } 2453 list_add_tail(&dup_mode->head, &list); 2454 } 2455 } 2456 2457 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2458 if (!connector->encoder) 2459 continue; 2460 if (connector->encoder->crtc == crtc) 2461 list_move_tail(list.next, &connector->user_modes); 2462 } 2463 2464 MPASS(!list_empty(&list)); 2465 2466 out: 2467 list_for_each_entry_safe(dup_mode, next, &list, head) 2468 drm_mode_destroy(dev, dup_mode); 2469 2470 return ret; 2471} 2472 2473static int drm_mode_detachmode(struct drm_device *dev, 2474 struct drm_connector *connector, 2475 struct drm_display_mode *mode) 2476{ 2477 int found = 0; 2478 int ret = 0; 2479 struct drm_display_mode *match_mode, *t; 2480 2481 list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { 2482 if (drm_mode_equal(match_mode, mode)) { 2483 list_del(&match_mode->head); 2484 drm_mode_destroy(dev, match_mode); 2485 found = 1; 2486 break; 2487 } 2488 } 2489 2490 if (!found) 2491 ret = -EINVAL; 2492 2493 return ret; 2494} 2495 2496int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) 2497{ 2498 struct drm_connector *connector; 2499 2500 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2501 drm_mode_detachmode(dev, connector, mode); 2502 } 2503 return 0; 2504} 2505 2506/** 2507 * drm_fb_attachmode - Attach a user mode to an connector 2508 * @inode: inode from the ioctl 2509 * @filp: file * from the ioctl 2510 * @cmd: cmd from ioctl 2511 * @arg: arg from ioctl 2512 * 2513 * This attaches a user specified mode to an connector. 2514 * Called by the user via ioctl. 2515 * 2516 * RETURNS: 2517 * Zero on success, errno on failure. 2518 */ 2519int drm_mode_attachmode_ioctl(struct drm_device *dev, 2520 void *data, struct drm_file *file_priv) 2521{ 2522 struct drm_mode_mode_cmd *mode_cmd = data; 2523 struct drm_connector *connector; 2524 struct drm_display_mode *mode; 2525 struct drm_mode_object *obj; 2526 struct drm_mode_modeinfo *umode = &mode_cmd->mode; 2527 int ret = 0; 2528 2529 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2530 return -EINVAL; 2531 2532 sx_xlock(&dev->mode_config.mutex); 2533 2534 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); 2535 if (!obj) { 2536 ret = -EINVAL; 2537 goto out; 2538 } 2539 connector = obj_to_connector(obj); 2540 2541 mode = drm_mode_create(dev); 2542 if (!mode) { 2543 ret = -ENOMEM; 2544 goto out; 2545 } 2546 2547 ret = drm_crtc_convert_umode(mode, umode); 2548 if (ret) { 2549 DRM_DEBUG_KMS("Invalid mode\n"); 2550 drm_mode_destroy(dev, mode); 2551 goto out; 2552 } 2553 2554 drm_mode_attachmode(dev, connector, mode); 2555out: 2556 sx_xunlock(&dev->mode_config.mutex); 2557 return ret; 2558} 2559 2560 2561/** 2562 * drm_fb_detachmode - Detach a user specified mode from an connector 2563 * @inode: inode from the ioctl 2564 * @filp: file * from the ioctl 2565 * @cmd: cmd from ioctl 2566 * @arg: arg from ioctl 2567 * 2568 * Called by the user via ioctl. 2569 * 2570 * RETURNS: 2571 * Zero on success, errno on failure. 2572 */ 2573int drm_mode_detachmode_ioctl(struct drm_device *dev, 2574 void *data, struct drm_file *file_priv) 2575{ 2576 struct drm_mode_object *obj; 2577 struct drm_mode_mode_cmd *mode_cmd = data; 2578 struct drm_connector *connector; 2579 struct drm_display_mode mode; 2580 struct drm_mode_modeinfo *umode = &mode_cmd->mode; 2581 int ret = 0; 2582 2583 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2584 return -EINVAL; 2585 2586 sx_xlock(&dev->mode_config.mutex); 2587 2588 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); 2589 if (!obj) { 2590 ret = -EINVAL; 2591 goto out; 2592 } 2593 connector = obj_to_connector(obj); 2594 2595 ret = drm_crtc_convert_umode(&mode, umode); 2596 if (ret) { 2597 DRM_DEBUG_KMS("Invalid mode\n"); 2598 goto out; 2599 } 2600 2601 ret = drm_mode_detachmode(dev, connector, &mode); 2602out: 2603 sx_xunlock(&dev->mode_config.mutex); 2604 return ret; 2605} 2606 2607struct drm_property *drm_property_create(struct drm_device *dev, int flags, 2608 const char *name, int num_values) 2609{ 2610 struct drm_property *property = NULL; 2611 int ret; 2612 2613 property = malloc(sizeof(struct drm_property), DRM_MEM_KMS, 2614 M_WAITOK | M_ZERO); 2615 2616 if (num_values) { 2617 property->values = malloc(sizeof(uint64_t)*num_values, DRM_MEM_KMS, 2618 M_WAITOK | M_ZERO); 2619 } 2620 2621 ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 2622 if (ret) 2623 goto fail; 2624 property->flags = flags; 2625 property->num_values = num_values; 2626 INIT_LIST_HEAD(&property->enum_blob_list); 2627 2628 if (name) { 2629 strncpy(property->name, name, DRM_PROP_NAME_LEN); 2630 property->name[DRM_PROP_NAME_LEN-1] = '\0'; 2631 } 2632 2633 list_add_tail(&property->head, &dev->mode_config.property_list); 2634 return property; 2635 2636fail: 2637 free(property->values, DRM_MEM_KMS); 2638 free(property, DRM_MEM_KMS); 2639 return (NULL); 2640} 2641 2642struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 2643 const char *name, 2644 const struct drm_prop_enum_list *props, 2645 int num_values) 2646{ 2647 struct drm_property *property; 2648 int i, ret; 2649 2650 flags |= DRM_MODE_PROP_ENUM; 2651 2652 property = drm_property_create(dev, flags, name, num_values); 2653 if (!property) 2654 return NULL; 2655 2656 for (i = 0; i < num_values; i++) { 2657 ret = drm_property_add_enum(property, i, 2658 props[i].type, 2659 props[i].name); 2660 if (ret) { 2661 drm_property_destroy(dev, property); 2662 return NULL; 2663 } 2664 } 2665 2666 return property; 2667} 2668 2669struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 2670 const char *name, 2671 uint64_t min, uint64_t max) 2672{ 2673 struct drm_property *property; 2674 2675 flags |= DRM_MODE_PROP_RANGE; 2676 2677 property = drm_property_create(dev, flags, name, 2); 2678 if (!property) 2679 return NULL; 2680 2681 property->values[0] = min; 2682 property->values[1] = max; 2683 2684 return property; 2685} 2686 2687int drm_property_add_enum(struct drm_property *property, int index, 2688 uint64_t value, const char *name) 2689{ 2690 struct drm_property_enum *prop_enum; 2691 2692 if (!(property->flags & DRM_MODE_PROP_ENUM)) 2693 return -EINVAL; 2694 2695 if (!list_empty(&property->enum_blob_list)) { 2696 list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 2697 if (prop_enum->value == value) { 2698 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 2699 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 2700 return 0; 2701 } 2702 } 2703 } 2704 2705 prop_enum = malloc(sizeof(struct drm_property_enum), DRM_MEM_KMS, 2706 M_WAITOK | M_ZERO); 2707 2708 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 2709 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 2710 prop_enum->value = value; 2711 2712 property->values[index] = value; 2713 list_add_tail(&prop_enum->head, &property->enum_blob_list); 2714 return 0; 2715} 2716 2717void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 2718{ 2719 struct drm_property_enum *prop_enum, *pt; 2720 2721 list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { 2722 list_del(&prop_enum->head); 2723 free(prop_enum, DRM_MEM_KMS); 2724 } 2725 2726 if (property->num_values) 2727 free(property->values, DRM_MEM_KMS); 2728 drm_mode_object_put(dev, &property->base); 2729 list_del(&property->head); 2730 free(property, DRM_MEM_KMS); 2731} 2732 2733int drm_connector_attach_property(struct drm_connector *connector, 2734 struct drm_property *property, uint64_t init_val) 2735{ 2736 int i; 2737 2738 for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 2739 if (connector->property_ids[i] == 0) { 2740 connector->property_ids[i] = property->base.id; 2741 connector->property_values[i] = init_val; 2742 break; 2743 } 2744 } 2745 2746 if (i == DRM_CONNECTOR_MAX_PROPERTY) 2747 return -EINVAL; 2748 return 0; 2749} 2750 2751int drm_connector_property_set_value(struct drm_connector *connector, 2752 struct drm_property *property, uint64_t value) 2753{ 2754 int i; 2755 2756 for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 2757 if (connector->property_ids[i] == property->base.id) { 2758 connector->property_values[i] = value; 2759 break; 2760 } 2761 } 2762 2763 if (i == DRM_CONNECTOR_MAX_PROPERTY) 2764 return -EINVAL; 2765 return 0; 2766} 2767 2768int drm_connector_property_get_value(struct drm_connector *connector, 2769 struct drm_property *property, uint64_t *val) 2770{ 2771 int i; 2772 2773 for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 2774 if (connector->property_ids[i] == property->base.id) { 2775 *val = connector->property_values[i]; 2776 break; 2777 } 2778 } 2779 2780 if (i == DRM_CONNECTOR_MAX_PROPERTY) 2781 return -EINVAL; 2782 return 0; 2783} 2784 2785int drm_mode_getproperty_ioctl(struct drm_device *dev, 2786 void *data, struct drm_file *file_priv) 2787{ 2788 struct drm_mode_object *obj; 2789 struct drm_mode_get_property *out_resp = data; 2790 struct drm_property *property; 2791 int enum_count = 0; 2792 int blob_count = 0; 2793 int value_count = 0; 2794 int ret = 0, i; 2795 int copied; 2796 struct drm_property_enum *prop_enum; 2797 struct drm_mode_property_enum __user *enum_ptr; 2798 struct drm_property_blob *prop_blob; 2799 uint32_t *blob_id_ptr; 2800 uint64_t *values_ptr; 2801 uint32_t *blob_length_ptr; 2802 2803 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2804 return -EINVAL; 2805 2806 sx_xlock(&dev->mode_config.mutex); 2807 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); 2808 if (!obj) { 2809 ret = -EINVAL; 2810 goto done; 2811 } 2812 property = obj_to_property(obj); 2813 2814 if (property->flags & DRM_MODE_PROP_ENUM) { 2815 list_for_each_entry(prop_enum, &property->enum_blob_list, head) 2816 enum_count++; 2817 } else if (property->flags & DRM_MODE_PROP_BLOB) { 2818 list_for_each_entry(prop_blob, &property->enum_blob_list, head) 2819 blob_count++; 2820 } 2821 2822 value_count = property->num_values; 2823 2824 strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 2825 out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 2826 out_resp->flags = property->flags; 2827 2828 if ((out_resp->count_values >= value_count) && value_count) { 2829 values_ptr = (uint64_t *)(uintptr_t)out_resp->values_ptr; 2830 for (i = 0; i < value_count; i++) { 2831 if (copyout(&property->values[i], values_ptr + i, sizeof(uint64_t))) { 2832 ret = -EFAULT; 2833 goto done; 2834 } 2835 } 2836 } 2837 out_resp->count_values = value_count; 2838 2839 if (property->flags & DRM_MODE_PROP_ENUM) { 2840 if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 2841 copied = 0; 2842 enum_ptr = (struct drm_mode_property_enum *)(uintptr_t)out_resp->enum_blob_ptr; 2843 list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 2844 2845 if (copyout(&prop_enum->value, &enum_ptr[copied].value, sizeof(uint64_t))) { 2846 ret = -EFAULT; 2847 goto done; 2848 } 2849 2850 if (copyout(&prop_enum->name, 2851 &enum_ptr[copied].name,DRM_PROP_NAME_LEN)) { 2852 ret = -EFAULT; 2853 goto done; 2854 } 2855 copied++; 2856 } 2857 } 2858 out_resp->count_enum_blobs = enum_count; 2859 } 2860 2861 if (property->flags & DRM_MODE_PROP_BLOB) { 2862 if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { 2863 copied = 0; 2864 blob_id_ptr = (uint32_t *)(uintptr_t)out_resp->enum_blob_ptr; 2865 blob_length_ptr = (uint32_t *)(uintptr_t)out_resp->values_ptr; 2866 2867 list_for_each_entry(prop_blob, &property->enum_blob_list, head) { 2868 if (copyout(&prop_blob->base.id, 2869 blob_id_ptr + copied, sizeof(uint32_t))) { 2870 ret = -EFAULT; 2871 goto done; 2872 } 2873 2874 if (copyout(&prop_blob->length, 2875 blob_length_ptr + copied, sizeof(uint32_t))) { 2876 ret = -EFAULT; 2877 goto done; 2878 } 2879 2880 copied++; 2881 } 2882 } 2883 out_resp->count_enum_blobs = blob_count; 2884 } 2885done: 2886 sx_xunlock(&dev->mode_config.mutex); 2887 return ret; 2888} 2889 2890static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, 2891 void *data) 2892{ 2893 struct drm_property_blob *blob; 2894 int ret; 2895 2896 if (!length || !data) 2897 return NULL; 2898 2899 blob = malloc(sizeof(struct drm_property_blob) + length, DRM_MEM_KMS, 2900 M_WAITOK | M_ZERO); 2901 2902 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 2903 if (ret) { 2904 free(blob, DRM_MEM_KMS); 2905 return (NULL); 2906 } 2907 2908 blob->length = length; 2909 2910 memcpy(blob->data, data, length); 2911 2912 list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 2913 return blob; 2914} 2915 2916static void drm_property_destroy_blob(struct drm_device *dev, 2917 struct drm_property_blob *blob) 2918{ 2919 drm_mode_object_put(dev, &blob->base); 2920 list_del(&blob->head); 2921 free(blob, DRM_MEM_KMS); 2922} 2923 2924int drm_mode_getblob_ioctl(struct drm_device *dev, 2925 void *data, struct drm_file *file_priv) 2926{ 2927 struct drm_mode_object *obj; 2928 struct drm_mode_get_blob *out_resp = data; 2929 struct drm_property_blob *blob; 2930 int ret = 0; 2931 void *blob_ptr; 2932 2933 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2934 return -EINVAL; 2935 2936 sx_xlock(&dev->mode_config.mutex); 2937 obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); 2938 if (!obj) { 2939 ret = -EINVAL; 2940 goto done; 2941 } 2942 blob = obj_to_blob(obj); 2943 2944 if (out_resp->length == blob->length) { 2945 blob_ptr = (void *)(unsigned long)out_resp->data; 2946 if (copyout(blob->data, blob_ptr, blob->length)){ 2947 ret = -EFAULT; 2948 goto done; 2949 } 2950 } 2951 out_resp->length = blob->length; 2952 2953done: 2954 sx_xunlock(&dev->mode_config.mutex); 2955 return ret; 2956} 2957 2958int drm_mode_connector_update_edid_property(struct drm_connector *connector, 2959 struct edid *edid) 2960{ 2961 struct drm_device *dev = connector->dev; 2962 int ret = 0, size; 2963 2964 if (connector->edid_blob_ptr) 2965 drm_property_destroy_blob(dev, connector->edid_blob_ptr); 2966 2967 /* Delete edid, when there is none. */ 2968 if (!edid) { 2969 connector->edid_blob_ptr = NULL; 2970 ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); 2971 return ret; 2972 } 2973 2974 size = EDID_LENGTH * (1 + edid->extensions); 2975 connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 2976 size, edid); 2977 2978 ret = drm_connector_property_set_value(connector, 2979 dev->mode_config.edid_property, 2980 connector->edid_blob_ptr->base.id); 2981 2982 return ret; 2983} 2984 2985int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 2986 void *data, struct drm_file *file_priv) 2987{ 2988 struct drm_mode_connector_set_property *out_resp = data; 2989 struct drm_mode_object *obj; 2990 struct drm_property *property; 2991 struct drm_connector *connector; 2992 int ret = -EINVAL; 2993 int i; 2994 2995 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2996 return -EINVAL; 2997 2998 sx_xlock(&dev->mode_config.mutex); 2999 3000 obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); 3001 if (!obj) { 3002 goto out; 3003 } 3004 connector = obj_to_connector(obj); 3005 3006 for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { 3007 if (connector->property_ids[i] == out_resp->prop_id) 3008 break; 3009 } 3010 3011 if (i == DRM_CONNECTOR_MAX_PROPERTY) { 3012 goto out; 3013 } 3014 3015 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); 3016 if (!obj) { 3017 goto out; 3018 } 3019 property = obj_to_property(obj); 3020 3021 if (property->flags & DRM_MODE_PROP_IMMUTABLE) 3022 goto out; 3023 3024 if (property->flags & DRM_MODE_PROP_RANGE) { 3025 if (out_resp->value < property->values[0]) 3026 goto out; 3027 3028 if (out_resp->value > property->values[1]) 3029 goto out; 3030 } else { 3031 int found = 0; 3032 for (i = 0; i < property->num_values; i++) { 3033 if (property->values[i] == out_resp->value) { 3034 found = 1; 3035 break; 3036 } 3037 } 3038 if (!found) { 3039 goto out; 3040 } 3041 } 3042 3043 /* Do DPMS ourselves */ 3044 if (property == connector->dev->mode_config.dpms_property) { 3045 if (connector->funcs->dpms) 3046 (*connector->funcs->dpms)(connector, (int) out_resp->value); 3047 ret = 0; 3048 } else if (connector->funcs->set_property) 3049 ret = connector->funcs->set_property(connector, property, out_resp->value); 3050 3051 /* store the property value if successful */ 3052 if (!ret) 3053 drm_connector_property_set_value(connector, property, out_resp->value); 3054out: 3055 sx_xunlock(&dev->mode_config.mutex); 3056 return ret; 3057} 3058 3059int drm_mode_connector_attach_encoder(struct drm_connector *connector, 3060 struct drm_encoder *encoder) 3061{ 3062 int i; 3063 3064 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 3065 if (connector->encoder_ids[i] == 0) { 3066 connector->encoder_ids[i] = encoder->base.id; 3067 return 0; 3068 } 3069 } 3070 return -ENOMEM; 3071} 3072 3073void drm_mode_connector_detach_encoder(struct drm_connector *connector, 3074 struct drm_encoder *encoder) 3075{ 3076 int i; 3077 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 3078 if (connector->encoder_ids[i] == encoder->base.id) { 3079 connector->encoder_ids[i] = 0; 3080 if (connector->encoder == encoder) 3081 connector->encoder = NULL; 3082 break; 3083 } 3084 } 3085} 3086 3087int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 3088 int gamma_size) 3089{ 3090 crtc->gamma_size = gamma_size; 3091 3092 crtc->gamma_store = malloc(gamma_size * sizeof(uint16_t) * 3, 3093 DRM_MEM_KMS, M_WAITOK | M_ZERO); 3094 3095 return 0; 3096} 3097 3098int drm_mode_gamma_set_ioctl(struct drm_device *dev, 3099 void *data, struct drm_file *file_priv) 3100{ 3101 struct drm_mode_crtc_lut *crtc_lut = data; 3102 struct drm_mode_object *obj; 3103 struct drm_crtc *crtc; 3104 void *r_base, *g_base, *b_base; 3105 int size; 3106 int ret = 0; 3107 3108 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3109 return -EINVAL; 3110 3111 sx_xlock(&dev->mode_config.mutex); 3112 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 3113 if (!obj) { 3114 ret = -EINVAL; 3115 goto out; 3116 } 3117 crtc = obj_to_crtc(obj); 3118 3119 /* memcpy into gamma store */ 3120 if (crtc_lut->gamma_size != crtc->gamma_size) { 3121 ret = -EINVAL; 3122 goto out; 3123 } 3124 3125 size = crtc_lut->gamma_size * (sizeof(uint16_t)); 3126 r_base = crtc->gamma_store; 3127 if (copyin((void *)(uintptr_t)crtc_lut->red, r_base, size)) { 3128 ret = -EFAULT; 3129 goto out; 3130 } 3131 3132 g_base = (char *)r_base + size; 3133 if (copyin((void *)(uintptr_t)crtc_lut->green, g_base, size)) { 3134 ret = -EFAULT; 3135 goto out; 3136 } 3137 3138 b_base = (char *)g_base + size; 3139 if (copyin((void *)(uintptr_t)crtc_lut->blue, b_base, size)) { 3140 ret = -EFAULT; 3141 goto out; 3142 } 3143 3144 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 3145 3146out: 3147 sx_xunlock(&dev->mode_config.mutex); 3148 return ret; 3149 3150} 3151 3152int drm_mode_gamma_get_ioctl(struct drm_device *dev, 3153 void *data, struct drm_file *file_priv) 3154{ 3155 struct drm_mode_crtc_lut *crtc_lut = data; 3156 struct drm_mode_object *obj; 3157 struct drm_crtc *crtc; 3158 void *r_base, *g_base, *b_base; 3159 int size; 3160 int ret = 0; 3161 3162 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3163 return -EINVAL; 3164 3165 sx_xlock(&dev->mode_config.mutex); 3166 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 3167 if (!obj) { 3168 ret = -EINVAL; 3169 goto out; 3170 } 3171 crtc = obj_to_crtc(obj); 3172 3173 /* memcpy into gamma store */ 3174 if (crtc_lut->gamma_size != crtc->gamma_size) { 3175 ret = -EINVAL; 3176 goto out; 3177 } 3178 3179 size = crtc_lut->gamma_size * (sizeof(uint16_t)); 3180 r_base = crtc->gamma_store; 3181 if (copyout(r_base, (void *)(uintptr_t)crtc_lut->red, size)) { 3182 ret = -EFAULT; 3183 goto out; 3184 } 3185 3186 g_base = (char *)r_base + size; 3187 if (copyout(g_base, (void *)(uintptr_t)crtc_lut->green, size)) { 3188 ret = -EFAULT; 3189 goto out; 3190 } 3191 3192 b_base = (char *)g_base + size; 3193 if (copyout(b_base, (void *)(uintptr_t)crtc_lut->blue, size)) { 3194 ret = -EFAULT; 3195 goto out; 3196 } 3197out: 3198 sx_xunlock(&dev->mode_config.mutex); 3199 return ret; 3200} 3201 3202static void 3203drm_kms_free(void *arg) 3204{ 3205 3206 free(arg, DRM_MEM_KMS); 3207} 3208 3209int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, 3210 struct drm_file *file_priv) 3211{ 3212 struct drm_mode_crtc_page_flip *page_flip = data; 3213 struct drm_mode_object *obj; 3214 struct drm_crtc *crtc; 3215 struct drm_framebuffer *fb; 3216 struct drm_pending_vblank_event *e = NULL; 3217 int ret = EINVAL; 3218 3219 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 3220 page_flip->reserved != 0) 3221 return (EINVAL); 3222 3223 sx_xlock(&dev->mode_config.mutex); 3224 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); 3225 if (!obj) 3226 goto out; 3227 crtc = obj_to_crtc(obj); 3228 3229 if (crtc->fb == NULL) { 3230 /* The framebuffer is currently unbound, presumably 3231 * due to a hotplug event, that userspace has not 3232 * yet discovered. 3233 */ 3234 ret = EBUSY; 3235 goto out; 3236 } 3237 3238 if (crtc->funcs->page_flip == NULL) 3239 goto out; 3240 3241 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); 3242 if (!obj) 3243 goto out; 3244 fb = obj_to_fb(obj); 3245 3246 if (crtc->mode.hdisplay > fb->width || 3247 crtc->mode.vdisplay > fb->height || 3248 crtc->x > fb->width - crtc->mode.hdisplay || 3249 crtc->y > fb->height - crtc->mode.vdisplay) { 3250 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n", 3251 fb->width, fb->height, 3252 crtc->mode.hdisplay, crtc->mode.vdisplay, 3253 crtc->x, crtc->y); 3254 ret = ENOSPC; 3255 goto out; 3256 } 3257 3258 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 3259 ret = ENOMEM; 3260 mtx_lock(&dev->event_lock); 3261 if (file_priv->event_space < sizeof e->event) { 3262 mtx_unlock(&dev->event_lock); 3263 goto out; 3264 } 3265 file_priv->event_space -= sizeof e->event; 3266 mtx_unlock(&dev->event_lock); 3267 3268 e = malloc(sizeof *e, DRM_MEM_KMS, M_WAITOK | M_ZERO); 3269 3270 e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 3271 e->event.base.length = sizeof e->event; 3272 e->event.user_data = page_flip->user_data; 3273 e->base.event = &e->event.base; 3274 e->base.file_priv = file_priv; 3275 e->base.destroy = 3276 (void (*) (struct drm_pending_event *))drm_kms_free; 3277 } 3278 3279 ret = -crtc->funcs->page_flip(crtc, fb, e); 3280 if (ret != 0) { 3281 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 3282 mtx_lock(&dev->event_lock); 3283 file_priv->event_space += sizeof e->event; 3284 mtx_unlock(&dev->event_lock); 3285 free(e, DRM_MEM_KMS); 3286 } 3287 } 3288 3289out: 3290 sx_xunlock(&dev->mode_config.mutex); 3291 CTR3(KTR_DRM, "page_flip_ioctl %d %d %d", curproc->p_pid, 3292 page_flip->crtc_id, ret); 3293 return (ret); 3294} 3295 3296void drm_mode_config_reset(struct drm_device *dev) 3297{ 3298 struct drm_crtc *crtc; 3299 struct drm_encoder *encoder; 3300 struct drm_connector *connector; 3301 3302 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 3303 if (crtc->funcs->reset) 3304 crtc->funcs->reset(crtc); 3305 3306 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 3307 if (encoder->funcs->reset) 3308 encoder->funcs->reset(encoder); 3309 3310 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 3311 if (connector->funcs->reset) 3312 connector->funcs->reset(connector); 3313} 3314 3315int drm_mode_create_dumb_ioctl(struct drm_device *dev, 3316 void *data, struct drm_file *file_priv) 3317{ 3318 struct drm_mode_create_dumb *args = data; 3319 3320 if (!dev->driver->dumb_create) 3321 return -ENOTSUP; 3322 return dev->driver->dumb_create(file_priv, dev, args); 3323} 3324 3325int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 3326 void *data, struct drm_file *file_priv) 3327{ 3328 struct drm_mode_map_dumb *args = data; 3329 3330 /* call driver ioctl to get mmap offset */ 3331 if (!dev->driver->dumb_map_offset) 3332 return -ENOTSUP; 3333 3334 return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 3335} 3336 3337int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 3338 void *data, struct drm_file *file_priv) 3339{ 3340 struct drm_mode_destroy_dumb *args = data; 3341 3342 if (!dev->driver->dumb_destroy) 3343 return -ENOTSUP; 3344 3345 return dev->driver->dumb_destroy(file_priv, dev, args->handle); 3346} 3347 3348/* 3349 * Just need to support RGB formats here for compat with code that doesn't 3350 * use pixel formats directly yet. 3351 */ 3352void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 3353 int *bpp) 3354{ 3355 switch (format) { 3356 case DRM_FORMAT_RGB332: 3357 case DRM_FORMAT_BGR233: 3358 *depth = 8; 3359 *bpp = 8; 3360 break; 3361 case DRM_FORMAT_XRGB1555: 3362 case DRM_FORMAT_XBGR1555: 3363 case DRM_FORMAT_RGBX5551: 3364 case DRM_FORMAT_BGRX5551: 3365 case DRM_FORMAT_ARGB1555: 3366 case DRM_FORMAT_ABGR1555: 3367 case DRM_FORMAT_RGBA5551: 3368 case DRM_FORMAT_BGRA5551: 3369 *depth = 15; 3370 *bpp = 16; 3371 break; 3372 case DRM_FORMAT_RGB565: 3373 case DRM_FORMAT_BGR565: 3374 *depth = 16; 3375 *bpp = 16; 3376 break; 3377 case DRM_FORMAT_RGB888: 3378 case DRM_FORMAT_BGR888: 3379 *depth = 24; 3380 *bpp = 24; 3381 break; 3382 case DRM_FORMAT_XRGB8888: 3383 case DRM_FORMAT_XBGR8888: 3384 case DRM_FORMAT_RGBX8888: 3385 case DRM_FORMAT_BGRX8888: 3386 *depth = 24; 3387 *bpp = 32; 3388 break; 3389 case DRM_FORMAT_XRGB2101010: 3390 case DRM_FORMAT_XBGR2101010: 3391 case DRM_FORMAT_RGBX1010102: 3392 case DRM_FORMAT_BGRX1010102: 3393 case DRM_FORMAT_ARGB2101010: 3394 case DRM_FORMAT_ABGR2101010: 3395 case DRM_FORMAT_RGBA1010102: 3396 case DRM_FORMAT_BGRA1010102: 3397 *depth = 30; 3398 *bpp = 32; 3399 break; 3400 case DRM_FORMAT_ARGB8888: 3401 case DRM_FORMAT_ABGR8888: 3402 case DRM_FORMAT_RGBA8888: 3403 case DRM_FORMAT_BGRA8888: 3404 *depth = 32; 3405 *bpp = 32; 3406 break; 3407 default: 3408 DRM_DEBUG_KMS("unsupported pixel format\n"); 3409 *depth = 0; 3410 *bpp = 0; 3411 break; 3412 } 3413} 3414