Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5059 → Rev 5060

/drivers/video/drm/drm_crtc.c
37,36 → 37,83
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_lock.h>
 
#include "drm_crtc_internal.h"
 
static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv);
 
/**
* drm_modeset_lock_all - take all modeset locks
* @dev: drm device
*
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented.
* scheme isn't (yet) implemented. Locks must be dropped with
* drm_modeset_unlock_all.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;
 
mutex_lock(&dev->mode_config.mutex);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;
 
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
mutex_lock(&config->mutex);
 
drm_modeset_acquire_init(ctx, 0);
 
retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
ret = drm_modeset_lock_all_crtcs(dev, ctx);
if (ret)
goto fail;
 
WARN_ON(config->acquire_ctx);
 
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_all():
*/
config->acquire_ctx = ctx;
 
drm_warn_on_modeset_not_all_locked(dev);
 
return;
 
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
}
EXPORT_SYMBOL(drm_modeset_lock_all);
 
/**
* drm_modeset_unlock_all - drop all modeset locks
* @dev: device
*
* This function drop all modeset locks taken by drm_modeset_lock_all.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
 
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_unlock(&crtc->mutex);
if (WARN_ON(!ctx))
return;
 
config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
 
kfree(ctx);
 
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
74,6 → 121,8
/**
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
* @dev: device
*
* Useful as a debug assert.
*/
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
80,8 → 129,9
struct drm_crtc *crtc;
 
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!mutex_is_locked(&crtc->mutex));
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
110,6 → 160,13
 
DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
 
static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
{
{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
};
 
/*
* Optional properties
*/
121,6 → 178,12
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
};
 
static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
{ DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
{ DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
{ DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
};
 
/*
* Non-global properties, but "required" for certain connectors.
*/
209,8 → 272,19
{ DRM_MODE_ENCODER_TVDAC, "TV" },
{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
{ DRM_MODE_ENCODER_DSI, "DSI" },
{ DRM_MODE_ENCODER_DPMST, "DP MST" },
};
 
static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
{
{ SubPixelUnknown, "Unknown" },
{ SubPixelHorizontalRGB, "Horizontal RGB" },
{ SubPixelHorizontalBGR, "Horizontal BGR" },
{ SubPixelVerticalRGB, "Vertical RGB" },
{ SubPixelVerticalBGR, "Vertical BGR" },
{ SubPixelNone, "None" },
};
 
void drm_connector_ida_init(void)
{
int i;
227,28 → 301,13
ida_destroy(&drm_connector_enum_list[i].ida);
}
 
const char *drm_get_encoder_name(const struct drm_encoder *encoder)
{
static char buf[32];
 
snprintf(buf, 32, "%s-%d",
drm_encoder_enum_list[encoder->encoder_type].name,
encoder->base.id);
return buf;
}
EXPORT_SYMBOL(drm_get_encoder_name);
 
const char *drm_get_connector_name(const struct drm_connector *connector)
{
static char buf[32];
 
snprintf(buf, 32, "%s-%d",
drm_connector_enum_list[connector->connector_type].name,
connector->connector_type_id);
return buf;
}
EXPORT_SYMBOL(drm_get_connector_name);
 
/**
* drm_get_connector_status_name - return a string for connector status
* @status: connector status to compute name of
*
* In contrast to the other drm_get_*_name functions this one here returns a
* const pointer and hence is threadsafe.
*/
const char *drm_get_connector_status_name(enum drm_connector_status status)
{
if (status == connector_status_connected)
260,11 → 319,33
}
EXPORT_SYMBOL(drm_get_connector_status_name);
 
/**
* drm_get_subpixel_order_name - return a string for a given subpixel enum
* @order: enum of subpixel_order
*
* Note you could abuse this and return something out of bounds, but that
* would be a caller error. No unscrubbed user data should make it here.
*/
const char *drm_get_subpixel_order_name(enum subpixel_order order)
{
return drm_subpixel_enum_list[order].name;
}
EXPORT_SYMBOL(drm_get_subpixel_order_name);
 
static char printable_char(int c)
{
return isascii(c) && isprint(c) ? c : '?';
}
 
/**
* drm_get_format_name - return a string for drm fourcc format
* @format: format to compute name of
*
* Note that the buffer used by this function is globally shared and owned by
* the function itself.
*
* FIXME: This isn't really multithreading safe.
*/
const char *drm_get_format_name(uint32_t format)
{
static char buf[32];
282,26 → 363,19
}
EXPORT_SYMBOL(drm_get_format_name);
 
/**
* drm_mode_object_get - allocate a new modeset identifier
* @dev: DRM device
* @obj: object pointer, used to generate unique ID
* @obj_type: object type
*
* Create a unique identifier based on @ptr in @dev's identifier space. Used
* for tracking modes, CRTCs and connectors.
*
* RETURNS:
* New unique (relative to other objects in @dev) integer identifier for the
* object.
/*
* Internal function to assign a slot in the object idr and optionally
* register the object into the idr.
*/
static int drm_mode_object_get(struct drm_device *dev,
struct drm_mode_object *obj, uint32_t obj_type)
static int drm_mode_object_get_reg(struct drm_device *dev,
struct drm_mode_object *obj,
uint32_t obj_type,
bool register_obj)
{
int ret;
 
mutex_lock(&dev->mode_config.idr_mutex);
ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
if (ret >= 0) {
/*
* Set up the object linking under the protection of the idr
316,13 → 390,44
}
 
/**
* drm_mode_object_get - allocate a new modeset identifier
* @dev: DRM device
* @obj: object pointer, used to generate unique ID
* @obj_type: object type
*
* Create a unique identifier based on @ptr in @dev's identifier space. Used
* for tracking modes, CRTCs and connectors. Note that despite the _get postfix
* modeset identifiers are _not_ reference counted. Hence don't use this for
* reference counted modeset objects like framebuffers.
*
* Returns:
* New unique (relative to other objects in @dev) integer identifier for the
* object.
*/
int drm_mode_object_get(struct drm_device *dev,
struct drm_mode_object *obj, uint32_t obj_type)
{
return drm_mode_object_get_reg(dev, obj, obj_type, true);
}
 
static void drm_mode_object_register(struct drm_device *dev,
struct drm_mode_object *obj)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
mutex_unlock(&dev->mode_config.idr_mutex);
}
 
/**
* drm_mode_object_put - free a modeset identifer
* @dev: DRM device
* @object: object to free
*
* Free @id from @dev's unique identifier pool.
* Free @id from @dev's unique identifier pool. Note that despite the _get
* postfix modeset identifiers are _not_ reference counted. Hence don't use this
* for reference counted modeset objects like framebuffers.
*/
static void drm_mode_object_put(struct drm_device *dev,
void drm_mode_object_put(struct drm_device *dev,
struct drm_mode_object *object)
{
mutex_lock(&dev->mode_config.idr_mutex);
330,6 → 435,25
mutex_unlock(&dev->mode_config.idr_mutex);
}
 
static struct drm_mode_object *_object_find(struct drm_device *dev,
uint32_t id, uint32_t type)
{
struct drm_mode_object *obj = NULL;
 
mutex_lock(&dev->mode_config.idr_mutex);
obj = idr_find(&dev->mode_config.crtc_idr, id);
if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
obj = NULL;
if (obj && obj->id != id)
obj = NULL;
/* don't leak out unref'd fb's */
if (obj && (obj->type == DRM_MODE_OBJECT_FB))
obj = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
 
return obj;
}
 
/**
* drm_mode_object_find - look up a drm object with static lifetime
* @dev: drm device
337,7 → 461,9
* @type: type of the mode object
*
* Note that framebuffers cannot be looked up with this functions - since those
* are reference counted, they need special treatment.
* are reference counted, they need special treatment. Even with
* DRM_MODE_OBJECT_ANY (although that will simply return NULL
* rather than WARN_ON()).
*/
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
uint32_t id, uint32_t type)
347,13 → 473,7
/* Framebuffers are reference counted and need their own lookup
* function.*/
WARN_ON(type == DRM_MODE_OBJECT_FB);
 
mutex_lock(&dev->mode_config.idr_mutex);
obj = idr_find(&dev->mode_config.crtc_idr, id);
if (!obj || (obj->type != type) || (obj->id != id))
obj = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
 
obj = _object_find(dev, id, type);
return obj;
}
EXPORT_SYMBOL(drm_mode_object_find);
373,7 → 493,7
* since all the fb attributes are invariant over its lifetime, no further
* locking but only correct reference counting is required.
*
* RETURNS:
* Returns:
* Zero on success, error code on failure.
*/
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
434,7 → 554,7
*
* If successful, this grabs an additional reference to the framebuffer -
* callers need to make sure to eventually unreference the returned framebuffer
* again.
* again, using @drm_framebuffer_unreference.
*/
struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
uint32_t id)
459,7 → 579,7
*/
void drm_framebuffer_unreference(struct drm_framebuffer *fb)
{
DRM_DEBUG("FB ID: %d\n", fb->base.id);
DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount));
kref_put(&fb->refcount, drm_framebuffer_free);
}
EXPORT_SYMBOL(drm_framebuffer_unreference);
467,10 → 587,12
/**
* drm_framebuffer_reference - incr the fb refcnt
* @fb: framebuffer
*
* This functions increments the fb's refcount.
*/
void drm_framebuffer_reference(struct drm_framebuffer *fb)
{
DRM_DEBUG("FB ID: %d\n", fb->base.id);
DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount));
kref_get(&fb->refcount);
}
EXPORT_SYMBOL(drm_framebuffer_reference);
482,7 → 604,7
 
static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
{
DRM_DEBUG("FB ID: %d\n", fb->base.id);
DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount));
kref_put(&fb->refcount, drm_framebuffer_free_bug);
}
 
523,8 → 645,9
* drm_framebuffer_cleanup - remove a framebuffer object
* @fb: framebuffer to remove
*
* Cleanup references to a user-created framebuffer. This function is intended
* to be used from the drivers ->destroy callback.
* Cleanup framebuffer. This function is intended to be used from the drivers
* ->destroy callback. It can also be used to clean up driver private
* framebuffers embedded into a larger structure.
*
* Note that this function does not remove the fb from active usuage - if it is
* still used anywhere, hilarity can ensue since userspace could call getfb on
587,7 → 710,7
drm_modeset_lock_all(dev);
/* remove from any CRTC */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb) {
if (crtc->primary->fb == fb) {
/* should turn off the crtc */
memset(&set, 0, sizeof(struct drm_mode_set));
set.crtc = crtc;
609,20 → 732,28
}
EXPORT_SYMBOL(drm_framebuffer_remove);
 
DEFINE_WW_CLASS(crtc_ww_class);
 
/**
* drm_crtc_init - Initialise a new CRTC object
* drm_crtc_init_with_planes - Initialise a new CRTC object with
* specified primary and cursor planes.
* @dev: DRM device
* @crtc: CRTC object to init
* @primary: Primary plane for CRTC
* @cursor: Cursor plane for CRTC
* @funcs: callbacks for the new CRTC
*
* Inits a new object created as base part of a driver crtc object.
*
* RETURNS:
* Returns:
* Zero on success, error code on failure.
*/
int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *primary,
struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs)
{
struct drm_mode_config *config = &dev->mode_config;
int ret;
 
crtc->dev = dev;
630,8 → 761,9
crtc->invert_dimensions = false;
 
drm_modeset_lock_all(dev);
mutex_init(&crtc->mutex);
mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
drm_modeset_lock_init(&crtc->mutex);
/* dropped by _unlock_all(): */
drm_modeset_lock(&crtc->mutex, config->acquire_ctx);
 
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
if (ret)
639,15 → 771,22
 
crtc->base.properties = &crtc->properties;
 
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
list_add_tail(&crtc->head, &config->crtc_list);
config->num_crtc++;
 
crtc->primary = primary;
crtc->cursor = cursor;
if (primary)
primary->possible_crtcs = 1 << drm_crtc_index(crtc);
if (cursor)
cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
out:
drm_modeset_unlock_all(dev);
 
return ret;
}
EXPORT_SYMBOL(drm_crtc_init);
EXPORT_SYMBOL(drm_crtc_init_with_planes);
 
/**
* drm_crtc_cleanup - Clean up the core crtc usage
664,6 → 803,8
kfree(crtc->gamma_store);
crtc->gamma_store = NULL;
 
drm_modeset_lock_fini(&crtc->mutex);
 
drm_mode_object_put(dev, &crtc->base);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
693,20 → 834,6
}
EXPORT_SYMBOL(drm_crtc_index);
 
/**
* drm_mode_probed_add - add a mode to a connector's probed mode list
* @connector: connector the new mode
* @mode: mode data
*
* Add @mode to @connector's mode list for later use.
*/
void drm_mode_probed_add(struct drm_connector *connector,
struct drm_display_mode *mode)
{
list_add_tail(&mode->head, &connector->probed_modes);
}
EXPORT_SYMBOL(drm_mode_probed_add);
 
/*
* drm_mode_remove - remove and free a mode
* @connector: connector list to modify
731,7 → 858,7
* Initialises a preallocated connector. Connectors should be
* subclassed as part of driver connector objects.
*
* RETURNS:
* Returns:
* Zero on success, error code on failure.
*/
int drm_connector_init(struct drm_device *dev,
745,9 → 872,9
 
drm_modeset_lock_all(dev);
 
ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false);
if (ret)
goto out;
goto out_unlock;
 
connector->base.properties = &connector->properties;
connector->dev = dev;
757,9 → 884,17
ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
if (connector->connector_type_id < 0) {
ret = connector->connector_type_id;
drm_mode_object_put(dev, &connector->base);
goto out;
goto out_put;
}
connector->name =
kasprintf(GFP_KERNEL, "%s-%d",
drm_connector_enum_list[connector_type].name,
connector->connector_type_id);
if (!connector->name) {
ret = -ENOMEM;
goto out_put;
}
 
INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes);
connector->edid_blob_ptr = NULL;
776,7 → 911,13
drm_object_attach_property(&connector->base,
dev->mode_config.dpms_property, 0);
 
out:
connector->debugfs_entry = NULL;
 
out_put:
if (ret)
drm_mode_object_put(dev, &connector->base);
 
out_unlock:
drm_modeset_unlock_all(dev);
 
return ret;
804,22 → 945,75
connector->connector_type_id);
 
drm_mode_object_put(dev, &connector->base);
kfree(connector->name);
connector->name = NULL;
list_del(&connector->head);
dev->mode_config.num_connector--;
}
EXPORT_SYMBOL(drm_connector_cleanup);
 
/**
* drm_connector_register - register a connector
* @connector: the connector to register
*
* Register userspace interfaces for a connector
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_connector_register(struct drm_connector *connector)
{
int ret;
 
drm_mode_object_register(connector->dev, &connector->base);
 
return 0;
}
EXPORT_SYMBOL(drm_connector_register);
 
/**
* drm_connector_unregister - unregister a connector
* @connector: the connector to unregister
*
* Unregister userspace interfaces for a connector
*/
void drm_connector_unregister(struct drm_connector *connector)
{
}
EXPORT_SYMBOL(drm_connector_unregister);
 
 
/**
* drm_connector_unplug_all - unregister connector userspace interfaces
* @dev: drm device
*
* This function unregisters all connector userspace interfaces in sysfs. Should
* be call when the device is disconnected, e.g. from an usb driver's
* ->disconnect callback.
*/
void drm_connector_unplug_all(struct drm_device *dev)
{
struct drm_connector *connector;
 
/* taking the mode config mutex ends up in a clash with sysfs */
// list_for_each_entry(connector, &dev->mode_config.connector_list, head)
// drm_sysfs_connector_remove(connector);
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
drm_connector_unregister(connector);
 
}
EXPORT_SYMBOL(drm_connector_unplug_all);
 
/**
* drm_bridge_init - initialize a drm transcoder/bridge
* @dev: drm device
* @bridge: transcoder/bridge to set up
* @funcs: bridge function table
*
* Initialises a preallocated bridge. Bridges should be
* subclassed as part of driver connector objects.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
const struct drm_bridge_funcs *funcs)
{
843,6 → 1037,12
}
EXPORT_SYMBOL(drm_bridge_init);
 
/**
* drm_bridge_cleanup - cleans up an initialised bridge
* @bridge: bridge to cleanup
*
* Cleans up the bridge but doesn't free the object.
*/
void drm_bridge_cleanup(struct drm_bridge *bridge)
{
struct drm_device *dev = bridge->dev;
855,6 → 1055,19
}
EXPORT_SYMBOL(drm_bridge_cleanup);
 
/**
* drm_encoder_init - Init a preallocated encoder
* @dev: drm device
* @encoder: the encoder to init
* @funcs: callbacks for this encoder
* @encoder_type: user visible type of the encoder
*
* Initialises a preallocated encoder. Encoder should be
* subclassed as part of driver encoder objects.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
866,16 → 1079,27
 
ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
if (ret)
goto out;
goto out_unlock;
 
encoder->dev = dev;
encoder->encoder_type = encoder_type;
encoder->funcs = funcs;
encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
drm_encoder_enum_list[encoder_type].name,
encoder->base.id);
if (!encoder->name) {
ret = -ENOMEM;
goto out_put;
}
 
list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
dev->mode_config.num_encoder++;
 
out:
out_put:
if (ret)
drm_mode_object_put(dev, &encoder->base);
 
out_unlock:
drm_modeset_unlock_all(dev);
 
return ret;
882,11 → 1106,19
}
EXPORT_SYMBOL(drm_encoder_init);
 
/**
* drm_encoder_cleanup - cleans up an initialised encoder
* @encoder: encoder to cleanup
*
* Cleans up the encoder but doesn't free the object.
*/
void drm_encoder_cleanup(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
drm_modeset_lock_all(dev);
drm_mode_object_put(dev, &encoder->base);
kfree(encoder->name);
encoder->name = NULL;
list_del(&encoder->head);
dev->mode_config.num_encoder--;
drm_modeset_unlock_all(dev);
894,7 → 1126,7
EXPORT_SYMBOL(drm_encoder_cleanup);
 
/**
* drm_plane_init - Initialise a new plane object
* drm_universal_plane_init - Initialize a new universal plane object
* @dev: DRM device
* @plane: plane object to init
* @possible_crtcs: bitmask of possible CRTCs
901,18 → 1133,18
* @funcs: callbacks for the new plane
* @formats: array of supported formats (%DRM_FORMAT_*)
* @format_count: number of elements in @formats
* @priv: plane is private (hidden from userspace)?
* @type: type of plane (overlay, primary, cursor)
*
* Inits a new object created as base part of a driver plane object.
* Initializes a plane object of type @type.
*
* RETURNS:
* Returns:
* Zero on success, error code on failure.
*/
int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, uint32_t format_count,
bool priv)
enum drm_plane_type type)
{
int ret;
 
937,23 → 1169,53
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
plane->format_count = format_count;
plane->possible_crtcs = possible_crtcs;
plane->type = type;
 
/* private planes are not exposed to userspace, but depending on
* display hardware, might be convenient to allow sharing programming
* for the scanout engine with the crtc implementation.
*/
if (!priv) {
list_add_tail(&plane->head, &dev->mode_config.plane_list);
dev->mode_config.num_plane++;
} else {
INIT_LIST_HEAD(&plane->head);
}
dev->mode_config.num_total_plane++;
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
dev->mode_config.num_overlay_plane++;
 
drm_object_attach_property(&plane->base,
dev->mode_config.plane_type_property,
plane->type);
 
out:
drm_modeset_unlock_all(dev);
 
return ret;
}
EXPORT_SYMBOL(drm_universal_plane_init);
 
/**
* drm_plane_init - Initialize a legacy plane
* @dev: DRM device
* @plane: plane object to init
* @possible_crtcs: bitmask of possible CRTCs
* @funcs: callbacks for the new plane
* @formats: array of supported formats (%DRM_FORMAT_*)
* @format_count: number of elements in @formats
* @is_primary: plane type (primary vs overlay)
*
* Legacy API to initialize a DRM plane.
*
* New drivers should call drm_universal_plane_init() instead.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, uint32_t format_count,
bool is_primary)
{
enum drm_plane_type type;
 
type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
formats, format_count, type);
}
EXPORT_SYMBOL(drm_plane_init);
 
/**
971,11 → 1233,13
drm_modeset_lock_all(dev);
kfree(plane->format_types);
drm_mode_object_put(dev, &plane->base);
/* if not added to a list, it must be a private plane */
if (!list_empty(&plane->head)) {
 
BUG_ON(list_empty(&plane->head));
 
list_del(&plane->head);
dev->mode_config.num_plane--;
}
dev->mode_config.num_total_plane--;
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
dev->mode_config.num_overlay_plane--;
drm_modeset_unlock_all(dev);
}
EXPORT_SYMBOL(drm_plane_cleanup);
991,69 → 1255,29
*/
void drm_plane_force_disable(struct drm_plane *plane)
{
struct drm_framebuffer *old_fb = plane->fb;
int ret;
 
if (!plane->fb)
if (!old_fb)
return;
 
ret = plane->funcs->disable_plane(plane);
if (ret)
if (ret) {
DRM_ERROR("failed to disable plane with busy fb\n");
return;
}
/* disconnect the plane from the fb and crtc: */
__drm_framebuffer_unreference(plane->fb);
__drm_framebuffer_unreference(old_fb);
plane->fb = NULL;
plane->crtc = NULL;
}
EXPORT_SYMBOL(drm_plane_force_disable);
 
/**
* drm_mode_create - create a new display mode
* @dev: DRM device
*
* Create a new drm_display_mode, give it an ID, and return it.
*
* RETURNS:
* Pointer to new mode on success, NULL on error.
*/
struct drm_display_mode *drm_mode_create(struct drm_device *dev)
{
struct drm_display_mode *nmode;
 
nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
if (!nmode)
return NULL;
 
if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
kfree(nmode);
return NULL;
}
 
return nmode;
}
EXPORT_SYMBOL(drm_mode_create);
 
/**
* drm_mode_destroy - remove a mode
* @dev: DRM device
* @mode: mode to remove
*
* Free @mode's unique identifier, then free it.
*/
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
{
if (!mode)
return;
 
drm_mode_object_put(dev, &mode->base);
 
kfree(mode);
}
EXPORT_SYMBOL(drm_mode_destroy);
 
static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
{
struct drm_property *edid;
struct drm_property *dpms;
struct drm_property *dev_path;
 
/*
* Standard properties (apply to all connectors)
1068,9 → 1292,30
ARRAY_SIZE(drm_dpms_enum_list));
dev->mode_config.dpms_property = dpms;
 
dev_path = drm_property_create(dev,
DRM_MODE_PROP_BLOB |
DRM_MODE_PROP_IMMUTABLE,
"PATH", 0);
dev->mode_config.path_property = dev_path;
 
return 0;
}
 
static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
{
struct drm_property *type;
 
/*
* Standard properties (apply to all planes)
*/
type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
"type", drm_plane_type_enum_list,
ARRAY_SIZE(drm_plane_type_enum_list));
dev->mode_config.plane_type_property = type;
 
return 0;
}
 
/**
* drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
* @dev: DRM device
1209,6 → 1454,33
EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
/**
* drm_mode_create_aspect_ratio_property - create aspect ratio property
* @dev: DRM device
*
* Called by a driver the first time it's needed, must be attached to desired
* connectors.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
{
if (dev->mode_config.aspect_ratio_property)
return 0;
 
dev->mode_config.aspect_ratio_property =
drm_property_create_enum(dev, 0, "aspect ratio",
drm_aspect_ratio_enum_list,
ARRAY_SIZE(drm_aspect_ratio_enum_list));
 
if (dev->mode_config.aspect_ratio_property == NULL)
return -ENOMEM;
 
return 0;
}
EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
 
/**
* drm_mode_create_dirty_property - create dirty property
* @dev: DRM device
*
1253,6 → 1525,16
return 0;
}
 
void drm_mode_group_destroy(struct drm_mode_group *group)
{
kfree(group->id_list);
group->id_list = NULL;
}
 
/*
* NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is
* the drm core's responsibility to set up mode control groups.
*/
int drm_mode_group_init_legacy_group(struct drm_device *dev,
struct drm_mode_group *group)
{
1285,6 → 1567,15
}
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
 
void drm_reinit_primary_mode_group(struct drm_device *dev)
{
drm_modeset_lock_all(dev);
drm_mode_group_destroy(&dev->primary->mode_group);
drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
drm_modeset_unlock_all(dev);
}
EXPORT_SYMBOL(drm_reinit_primary_mode_group);
 
/**
* drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
* @out: drm_mode_modeinfo struct to return to the user
1329,7 → 1620,7
* Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
* the caller.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
static int drm_crtc_convert_umode(struct drm_display_mode *out,
1374,7 → 1665,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getresources(struct drm_device *dev, void *data,
1427,9 → 1718,9
mutex_unlock(&file_priv->fbs_lock);
 
drm_modeset_lock_all(dev);
mode_group = &file_priv->master->minor->mode_group;
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
if (!drm_is_primary_client(file_priv)) {
 
mode_group = NULL;
list_for_each(lh, &dev->mode_config.crtc_list)
crtc_count++;
 
1440,6 → 1731,7
encoder_count++;
} else {
 
mode_group = &file_priv->master->minor->mode_group;
crtc_count = mode_group->num_crtcs;
connector_count = mode_group->num_connectors;
encoder_count = mode_group->num_encoders;
1454,7 → 1746,7
if (card_res->count_crtcs >= crtc_count) {
copied = 0;
crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
if (!mode_group) {
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
head) {
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
1481,12 → 1773,12
if (card_res->count_encoders >= encoder_count) {
copied = 0;
encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
if (!mode_group) {
list_for_each_entry(encoder,
&dev->mode_config.encoder_list,
head) {
DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
drm_get_encoder_name(encoder));
encoder->name);
if (put_user(encoder->base.id, encoder_id +
copied)) {
ret = -EFAULT;
1512,13 → 1804,13
if (card_res->count_connectors >= connector_count) {
copied = 0;
connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
if (!mode_group) {
list_for_each_entry(connector,
&dev->mode_config.connector_list,
head) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id,
drm_get_connector_name(connector));
connector->name);
if (put_user(connector->base.id,
connector_id + copied)) {
ret = -EFAULT;
1559,7 → 1851,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getcrtc(struct drm_device *dev,
1567,7 → 1859,6
{
struct drm_mode_crtc *crtc_resp = data;
struct drm_crtc *crtc;
struct drm_mode_object *obj;
int ret = 0;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
1575,19 → 1866,17
 
drm_modeset_lock_all(dev);
 
obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
}
crtc = obj_to_crtc(obj);
 
crtc_resp->x = crtc->x;
crtc_resp->y = crtc->y;
crtc_resp->gamma_size = crtc->gamma_size;
if (crtc->fb)
crtc_resp->fb_id = crtc->fb->base.id;
if (crtc->primary->fb)
crtc_resp->fb_id = crtc->primary->fb->base.id;
else
crtc_resp->fb_id = 0;
 
1628,7 → 1917,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getconnector(struct drm_device *dev, void *data,
1635,7 → 1924,6
struct drm_file *file_priv)
{
struct drm_mode_get_connector *out_resp = data;
struct drm_mode_object *obj;
struct drm_connector *connector;
struct drm_display_mode *mode;
int mode_count = 0;
1659,13 → 1947,11
 
mutex_lock(&dev->mode_config.mutex);
 
obj = drm_mode_object_find(dev, out_resp->connector_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!obj) {
connector = drm_connector_find(dev, out_resp->connector_id);
if (!connector) {
ret = -ENOENT;
goto out;
}
connector = obj_to_connector(obj);
 
props_count = connector->properties.count;
 
1693,10 → 1979,12
out_resp->mm_height = connector->display_info.height_mm;
out_resp->subpixel = connector->display_info.subpixel_order;
out_resp->connection = connector->status;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
if (connector->encoder)
out_resp->encoder_id = connector->encoder->base.id;
else
out_resp->encoder_id = 0;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
 
/*
* This ioctl is called twice, once to determine how much space is
1763,11 → 2051,23
return ret;
}
 
/**
* drm_mode_getencoder - get encoder configuration
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Construct a encoder configuration structure to return to the user.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getencoder(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_get_encoder *enc_resp = data;
struct drm_mode_object *obj;
struct drm_encoder *encoder;
int ret = 0;
 
1775,13 → 2075,11
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, enc_resp->encoder_id,
DRM_MODE_OBJECT_ENCODER);
if (!obj) {
encoder = drm_encoder_find(dev, enc_resp->encoder_id);
if (!encoder) {
ret = -ENOENT;
goto out;
}
encoder = obj_to_encoder(obj);
 
if (encoder->crtc)
enc_resp->crtc_id = encoder->crtc->base.id;
1798,12 → 2096,17
}
 
/**
* drm_mode_getplane_res - get plane info
* drm_mode_getplane_res - enumerate all plane resources
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* Return an plane count and set of IDs.
* Construct a list of plane ids to return to the user.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv)
1813,6 → 2116,7
struct drm_plane *plane;
uint32_t __user *plane_ptr;
int copied = 0, ret = 0;
unsigned num_planes;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
1820,15 → 2124,28
drm_modeset_lock_all(dev);
config = &dev->mode_config;
 
if (file_priv->universal_planes)
num_planes = config->num_total_plane;
else
num_planes = config->num_overlay_plane;
 
/*
* This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it.
*/
if (config->num_plane &&
(plane_resp->count_planes >= config->num_plane)) {
if (num_planes &&
(plane_resp->count_planes >= num_planes)) {
plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
list_for_each_entry(plane, &config->plane_list, head) {
/*
* Unless userspace set the 'universal planes'
* capability bit, only advertise overlays.
*/
if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
!file_priv->universal_planes)
continue;
 
if (put_user(plane->base.id, plane_ptr + copied)) {
ret = -EFAULT;
goto out;
1836,7 → 2153,7
copied++;
}
}
plane_resp->count_planes = config->num_plane;
plane_resp->count_planes = num_planes;
 
out:
drm_modeset_unlock_all(dev);
1844,19 → 2161,22
}
 
/**
* drm_mode_getplane - get plane info
* drm_mode_getplane - get plane configuration
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* Return plane info, including formats supported, gamma size, any
* current fb, etc.
* Construct a plane configuration structure to return to the user.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_get_plane *plane_resp = data;
struct drm_mode_object *obj;
struct drm_plane *plane;
uint32_t __user *format_ptr;
int ret = 0;
1865,13 → 2185,11
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, plane_resp->plane_id,
DRM_MODE_OBJECT_PLANE);
if (!obj) {
plane = drm_plane_find(dev, plane_resp->plane_id);
if (!plane) {
ret = -ENOENT;
goto out;
}
plane = obj_to_plane(obj);
 
if (plane->crtc)
plane_resp->crtc_id = plane->crtc->base.id;
1908,72 → 2226,52
return ret;
}
 
/**
* drm_mode_setplane - set up or tear down an plane
* @dev: DRM device
* @data: ioctl data*
* @file_priv: DRM file info
/*
* setplane_internal - setplane handler for internal callers
*
* Set plane info, including placement, fb, scaling, and other factors.
* Or pass a NULL fb to disable.
* Note that we assume an extra reference has already been taken on fb. If the
* update fails, this reference will be dropped before return; if it succeeds,
* the previous framebuffer (if any) will be unreferenced instead.
*
* src_{x,y,w,h} are provided in 16.16 fixed point format
*/
int drm_mode_setplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
static int setplane_internal(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int32_t crtc_x, int32_t crtc_y,
uint32_t crtc_w, uint32_t crtc_h,
/* src_{x,y,w,h} values are 16.16 fixed point */
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
struct drm_mode_set_plane *plane_req = data;
struct drm_mode_object *obj;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_framebuffer *fb = NULL, *old_fb = NULL;
struct drm_device *dev = plane->dev;
struct drm_framebuffer *old_fb = NULL;
int ret = 0;
unsigned int fb_width, fb_height;
int i;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
/*
* First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
obj = drm_mode_object_find(dev, plane_req->plane_id,
DRM_MODE_OBJECT_PLANE);
if (!obj) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
return -ENOENT;
}
plane = obj_to_plane(obj);
 
/* No fb means shut it down */
if (!plane_req->fb_id) {
if (!fb) {
drm_modeset_lock_all(dev);
old_fb = plane->fb;
plane->funcs->disable_plane(plane);
ret = plane->funcs->disable_plane(plane);
if (!ret) {
plane->crtc = NULL;
plane->fb = NULL;
} else {
old_fb = NULL;
}
drm_modeset_unlock_all(dev);
goto out;
}
 
obj = drm_mode_object_find(dev, plane_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
ret = -ENOENT;
/* Check whether this plane is usable on this CRTC */
if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
DRM_DEBUG_KMS("Invalid crtc for plane\n");
ret = -EINVAL;
goto out;
}
crtc = obj_to_crtc(obj);
 
fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
if (!fb) {
DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
plane_req->fb_id);
ret = -ENOENT;
goto out;
}
 
/* Check whether this plane supports the fb pixel format. */
for (i = 0; i < plane->format_count; i++)
if (fb->pixel_format == plane->format_types[i])
1989,47 → 2287,31
fb_height = fb->height << 16;
 
/* Make sure source coordinates are inside the fb. */
if (plane_req->src_w > fb_width ||
plane_req->src_x > fb_width - plane_req->src_w ||
plane_req->src_h > fb_height ||
plane_req->src_y > fb_height - plane_req->src_h) {
if (src_w > fb_width ||
src_x > fb_width - src_w ||
src_h > fb_height ||
src_y > fb_height - src_h) {
DRM_DEBUG_KMS("Invalid source coordinates "
"%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
plane_req->src_w >> 16,
((plane_req->src_w & 0xffff) * 15625) >> 10,
plane_req->src_h >> 16,
((plane_req->src_h & 0xffff) * 15625) >> 10,
plane_req->src_x >> 16,
((plane_req->src_x & 0xffff) * 15625) >> 10,
plane_req->src_y >> 16,
((plane_req->src_y & 0xffff) * 15625) >> 10);
src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
ret = -ENOSPC;
goto out;
}
 
/* Give drivers some help against integer overflows */
if (plane_req->crtc_w > INT_MAX ||
plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
plane_req->crtc_h > INT_MAX ||
plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
plane_req->crtc_w, plane_req->crtc_h,
plane_req->crtc_x, plane_req->crtc_y);
ret = -ERANGE;
goto out;
}
 
drm_modeset_lock_all(dev);
old_fb = plane->fb;
ret = plane->funcs->update_plane(plane, crtc, fb,
plane_req->crtc_x, plane_req->crtc_y,
plane_req->crtc_w, plane_req->crtc_h,
plane_req->src_x, plane_req->src_y,
plane_req->src_w, plane_req->src_h);
crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h);
if (!ret) {
old_fb = plane->fb;
plane->crtc = crtc;
plane->fb = fb;
fb = NULL;
} else {
old_fb = NULL;
}
drm_modeset_unlock_all(dev);
 
2040,7 → 2322,86
drm_framebuffer_unreference(old_fb);
 
return ret;
 
}
 
/**
* drm_mode_setplane - configure a plane's configuration
* @dev: DRM device
* @data: ioctl data*
* @file_priv: DRM file info
*
* Set plane configuration, including placement, fb, scaling, and other factors.
* Or pass a NULL fb to disable (planes may be disabled without providing a
* valid crtc).
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_setplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_set_plane *plane_req = data;
struct drm_mode_object *obj;
struct drm_plane *plane;
struct drm_crtc *crtc = NULL;
struct drm_framebuffer *fb = NULL;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
/* Give drivers some help against integer overflows */
if (plane_req->crtc_w > INT_MAX ||
plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
plane_req->crtc_h > INT_MAX ||
plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
plane_req->crtc_w, plane_req->crtc_h,
plane_req->crtc_x, plane_req->crtc_y);
return -ERANGE;
}
 
/*
* First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
obj = drm_mode_object_find(dev, plane_req->plane_id,
DRM_MODE_OBJECT_PLANE);
if (!obj) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
return -ENOENT;
}
plane = obj_to_plane(obj);
 
if (plane_req->fb_id) {
fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
if (!fb) {
DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
plane_req->fb_id);
return -ENOENT;
}
 
obj = drm_mode_object_find(dev, plane_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
return -ENOENT;
}
crtc = obj_to_crtc(obj);
}
 
/*
* setplane_internal will take care of deref'ing either the old or new
* framebuffer depending on success.
*/
return setplane_internal(plane, crtc, fb,
plane_req->crtc_x, plane_req->crtc_y,
plane_req->crtc_w, plane_req->crtc_h,
plane_req->src_x, plane_req->src_y,
plane_req->src_w, plane_req->src_h);
}
#endif
 
/**
2049,6 → 2410,9
*
* This is a little helper to wrap internal calls to the ->set_config driver
* interface. The only thing it adds is correct refcounting dance.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_set_config_internal(struct drm_mode_set *set)
{
2063,19 → 2427,19
* crtcs. Atomic modeset will have saner semantics ...
*/
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
tmp->old_fb = tmp->fb;
tmp->old_fb = tmp->primary->fb;
 
fb = set->fb;
 
ret = crtc->funcs->set_config(set);
if (ret == 0) {
/* crtc->fb must be updated by ->set_config, enforces this. */
WARN_ON(fb != crtc->fb);
crtc->primary->crtc = crtc;
crtc->primary->fb = fb;
}
 
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
if (tmp->fb)
drm_framebuffer_reference(tmp->fb);
if (tmp->primary->fb)
drm_framebuffer_reference(tmp->primary->fb);
// if (tmp->old_fb)
// drm_framebuffer_unreference(tmp->old_fb);
}
2085,11 → 2449,16
EXPORT_SYMBOL(drm_mode_set_config_internal);
 
#if 0
/*
* Checks that the framebuffer is big enough for the CRTC viewport
* (x, y, hdisplay, vdisplay)
/**
* drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
* CRTC viewport
* @crtc: CRTC that framebuffer will be displayed on
* @x: x panning
* @y: y panning
* @mode: mode that framebuffer will be displayed under
* @fb: framebuffer to check size of
*/
static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
int drm_crtc_check_viewport(const struct drm_crtc *crtc,
int x, int y,
const struct drm_display_mode *mode,
const struct drm_framebuffer *fb)
2123,6 → 2492,7
 
return 0;
}
EXPORT_SYMBOL(drm_crtc_check_viewport);
 
/**
* drm_mode_setcrtc - set CRTC configuration
2134,7 → 2504,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_setcrtc(struct drm_device *dev, void *data,
2142,7 → 2512,6
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_mode_crtc *crtc_req = data;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
struct drm_connector **connector_set = NULL, *connector;
struct drm_framebuffer *fb = NULL;
2160,14 → 2529,12
return -ERANGE;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, crtc_req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
ret = -ENOENT;
goto out;
}
crtc = obj_to_crtc(obj);
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
if (crtc_req->mode_valid) {
2174,12 → 2541,12
/* If we have a mode we need a framebuffer. */
/* If we pass -1, set the mode with the currently bound fb */
if (crtc_req->fb_id == -1) {
if (!crtc->fb) {
if (!crtc->primary->fb) {
DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
ret = -EINVAL;
goto out;
}
fb = crtc->fb;
fb = crtc->primary->fb;
/* Make refcounting symmetric with the lookup path. */
drm_framebuffer_reference(fb);
} else {
2250,18 → 2617,16
goto out;
}
 
obj = drm_mode_object_find(dev, out_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!obj) {
connector = drm_connector_find(dev, out_id);
if (!connector) {
DRM_DEBUG_KMS("Connector id %d unknown\n",
out_id);
ret = -ENOENT;
goto out;
}
connector = obj_to_connector(obj);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id,
drm_get_connector_name(connector));
connector->name);
 
connector_set[i] = connector;
}
2290,7 → 2655,6
struct drm_mode_cursor2 *req,
struct drm_file *file_priv)
{
struct drm_mode_object *obj;
struct drm_crtc *crtc;
int ret = 0;
 
2300,14 → 2664,20
if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
return -EINVAL;
 
obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
return -ENOENT;
}
crtc = obj_to_crtc(obj);
 
mutex_lock(&crtc->mutex);
/*
* If this crtc has a universal cursor plane, call that plane's update
* handler rather than using legacy cursor handlers.
*/
if (crtc->cursor)
return drm_mode_cursor_universal(crtc, req, file_priv);
 
drm_modeset_lock(&crtc->mutex, NULL);
if (req->flags & DRM_MODE_CURSOR_BO) {
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO;
2331,11 → 2701,26
}
}
out:
mutex_unlock(&crtc->mutex);
drm_modeset_unlock(&crtc->mutex);
 
return ret;
 
}
 
 
/**
* drm_mode_cursor_ioctl - set CRTC's cursor configuration
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Set the cursor configuration based on user request.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_cursor_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
2348,6 → 2733,21
return drm_mode_cursor_common(dev, &new_req, file_priv);
}
 
/**
* drm_mode_cursor2_ioctl - set CRTC's cursor configuration
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Set the cursor configuration based on user request. This implements the 2nd
* version of the cursor ioctl, which allows userspace to additionally specify
* the hotspot of the pointer.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_cursor2_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
2356,7 → 2756,14
}
#endif
 
/* Original addfb only supported RGB formats, so figure out which one */
/**
* drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
* @bpp: bits per pixels
* @depth: bit depth per pixel
*
* Computes a drm fourcc pixel format code for the given @bpp/@depth values.
* Useful in fbdev emulation code, since that deals in those values.
*/
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
{
uint32_t fmt;
2398,11 → 2805,12
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Add a new FB to the specified CRTC, given a user request.
* Add a new FB to the specified CRTC, given a user request. This is the
* original addfb ioclt which only supported RGB formats.
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_addfb(struct drm_device *dev,
2569,54 → 2977,38
return 0;
}
 
/**
* drm_mode_addfb2 - add an FB to the graphics configuration
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Add a new FB to the specified CRTC, given a user request with format.
*
* Called by the user via ioctl.
*
* RETURNS:
* Zero on success, errno on failure.
*/
int drm_mode_addfb2(struct drm_device *dev,
void *data, struct drm_file *file_priv)
static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv)
{
struct drm_mode_fb_cmd2 *r = data;
struct drm_mode_config *config = &dev->mode_config;
struct drm_framebuffer *fb;
int ret;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
if (r->flags & ~DRM_MODE_FB_INTERLACED) {
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
 
if ((config->min_width > r->width) || (r->width > config->max_width)) {
DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
r->width, config->min_width, config->max_width);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
if ((config->min_height > r->height) || (r->height > config->max_height)) {
DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
r->height, config->min_height, config->max_height);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
 
ret = framebuffer_check(r);
if (ret)
return ret;
return ERR_PTR(ret);
 
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n");
return PTR_ERR(fb);
return fb;
}
 
mutex_lock(&file_priv->fbs_lock);
2625,8 → 3017,37
DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
mutex_unlock(&file_priv->fbs_lock);
 
return fb;
}
 
return ret;
/**
* drm_mode_addfb2 - add an FB to the graphics configuration
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Add a new FB to the specified CRTC, given a user request with format. This is
* the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
* and uses fourcc codes as pixel format specifiers.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_addfb2(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_framebuffer *fb;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
fb = add_framebuffer_internal(dev, data, file_priv);
if (IS_ERR(fb))
return PTR_ERR(fb);
 
return 0;
}
 
/**
2639,7 → 3060,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_rmfb(struct drm_device *dev,
2693,7 → 3114,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getfb(struct drm_device *dev,
2737,6 → 3158,25
return ret;
}
 
/**
* drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
* Lookup the FB and flush out the damaged area supplied by userspace as a clip
* rectangle list. Generic userspace which does frontbuffer rendering must call
* this ioctl to flush out the changes on manual-update display outputs, e.g.
* usb display-link, mipi manual update panels or edp panel self refresh modes.
*
* Modesetting drivers which always update the frontbuffer do not need to
* implement the corresponding ->dirty framebuffer callback.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
2814,7 → 3254,7
*
* Called by the user via ioctl.
*
* RETURNS:
* Returns:
* Zero on success, errno on failure.
*/
void drm_fb_release(struct drm_file *priv)
2840,6 → 3280,20
#endif
 
 
/**
* drm_property_create - create a new property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @num_values: number of pre-defined values
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values)
{
2850,6 → 3304,8
if (!property)
return NULL;
 
property->dev = dev;
 
if (num_values) {
property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
if (!property->values)
2870,6 → 3326,9
}
 
list_add_tail(&property->head, &dev->mode_config.property_list);
 
WARN_ON(!drm_property_type_valid(property));
 
return property;
fail:
kfree(property->values);
2878,6 → 3337,24
}
EXPORT_SYMBOL(drm_property_create);
 
/**
* drm_property_create_enum - create a new enumeration property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @props: enumeration lists with property values
* @num_values: number of pre-defined values
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Userspace is only allowed to set one of the predefined values for enumeration
* properties.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
const char *name,
const struct drm_prop_enum_list *props,
2906,13 → 3383,33
}
EXPORT_SYMBOL(drm_property_create_enum);
 
/**
* drm_property_create_bitmask - create a new bitmask property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @props: enumeration lists with property bitflags
* @num_values: number of pre-defined values
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Compared to plain enumeration properties userspace is allowed to set any
* or'ed together combination of the predefined property bitflag values
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
int flags, const char *name,
const struct drm_prop_enum_list *props,
int num_values)
int num_props,
uint64_t supported_bits)
{
struct drm_property *property;
int i, ret;
int i, ret, index = 0;
int num_values = hweight64(supported_bits);
 
flags |= DRM_MODE_PROP_BITMASK;
 
2919,9 → 3416,16
property = drm_property_create(dev, flags, name, num_values);
if (!property)
return NULL;
for (i = 0; i < num_props; i++) {
if (!(supported_bits & (1ULL << props[i].type)))
continue;
 
for (i = 0; i < num_values; i++) {
ret = drm_property_add_enum(property, i,
if (WARN_ON(index >= num_values)) {
drm_property_destroy(dev, property);
return NULL;
}
 
ret = drm_property_add_enum(property, index++,
props[i].type,
props[i].name);
if (ret) {
2934,14 → 3438,12
}
EXPORT_SYMBOL(drm_property_create_bitmask);
 
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
static struct drm_property *property_create_range(struct drm_device *dev,
int flags, const char *name,
uint64_t min, uint64_t max)
{
struct drm_property *property;
 
flags |= DRM_MODE_PROP_RANGE;
 
property = drm_property_create(dev, flags, name, 2);
if (!property)
return NULL;
2951,14 → 3453,82
 
return property;
}
 
/**
* drm_property_create_range - create a new ranged property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @min: minimum value of the property
* @max: maximum value of the property
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Userspace is allowed to set any interger value in the (min, max) range
* inclusive.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
uint64_t min, uint64_t max)
{
return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
name, min, max);
}
EXPORT_SYMBOL(drm_property_create_range);
 
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int flags, const char *name,
int64_t min, int64_t max)
{
return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
name, I642U64(min), I642U64(max));
}
EXPORT_SYMBOL(drm_property_create_signed_range);
 
struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type)
{
struct drm_property *property;
 
flags |= DRM_MODE_PROP_OBJECT;
 
property = drm_property_create(dev, flags, name, 1);
if (!property)
return NULL;
 
property->values[0] = type;
 
return property;
}
EXPORT_SYMBOL(drm_property_create_object);
 
/**
* drm_property_add_enum - add a possible value to an enumeration property
* @property: enumeration property to change
* @index: index of the new enumeration
* @value: value of the new enumeration
* @name: symbolic name of the new enumeration
*
* This functions adds enumerations to a property.
*
* It's use is deprecated, drivers should use one of the more specific helpers
* to directly create the property with all enumerations already attached.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_property_add_enum(struct drm_property *property, int index,
uint64_t value, const char *name)
{
struct drm_property_enum *prop_enum;
 
if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
return -EINVAL;
 
/*
2965,7 → 3535,8
* Bitmask enum properties have the additional constraint of values
* from 0 to 63
*/
if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
(value > 63))
return -EINVAL;
 
if (!list_empty(&property->enum_blob_list)) {
2992,6 → 3563,14
}
EXPORT_SYMBOL(drm_property_add_enum);
 
/**
* drm_property_destroy - destroy a drm property
* @dev: drm device
* @property: property to destry
*
* This function frees a property including any attached resources like
* enumeration values.
*/
void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
{
struct drm_property_enum *prop_enum, *pt;
3009,6 → 3588,16
}
EXPORT_SYMBOL(drm_property_destroy);
 
/**
* drm_object_attach_property - attach a property to a modeset object
* @obj: drm modeset object
* @property: property to attach
* @init_val: initial value of the property
*
* This attaches the given property to the modeset object with the given initial
* value. Currently this function cannot fail since the properties are stored in
* a statically sized array.
*/
void drm_object_attach_property(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t init_val)
3029,6 → 3618,19
}
EXPORT_SYMBOL(drm_object_attach_property);
 
/**
* drm_object_property_set_value - set the value of a property
* @obj: drm mode object to set property value for
* @property: property to set
* @val: value the property should be set to
*
* This functions sets a given property on a given object. This function only
* changes the software state of the property, it does not call into the
* driver's ->set_property callback.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_object_property_set_value(struct drm_mode_object *obj,
struct drm_property *property, uint64_t val)
{
3045,6 → 3647,20
}
EXPORT_SYMBOL(drm_object_property_set_value);
 
/**
* drm_object_property_get_value - retrieve the value of a property
* @obj: drm mode object to get property value from
* @property: property to retrieve
* @val: storage for the property value
*
* This function retrieves the softare state of the given property for the given
* property. Since there is no driver callback to retrieve the current property
* value this might be out of sync with the hardware, depending upon the driver
* and property.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_object_property_get_value(struct drm_mode_object *obj,
struct drm_property *property, uint64_t *val)
{
3062,10 → 3678,22
EXPORT_SYMBOL(drm_object_property_get_value);
 
#if 0
/**
* drm_mode_getproperty_ioctl - get the current value of a connector's property
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* This function retrieves the current value for an connectors's property.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getproperty_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_object *obj;
struct drm_mode_get_property *out_resp = data;
struct drm_property *property;
int enum_count = 0;
3084,17 → 3712,17
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
if (!obj) {
property = drm_property_find(dev, out_resp->prop_id);
if (!property) {
ret = -ENOENT;
goto done;
}
property = obj_to_property(obj);
 
if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
list_for_each_entry(prop_enum, &property->enum_blob_list, head)
enum_count++;
} else if (property->flags & DRM_MODE_PROP_BLOB) {
} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
list_for_each_entry(prop_blob, &property->enum_blob_list, head)
blob_count++;
}
3116,7 → 3744,8
}
out_resp->count_values = value_count;
 
if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
copied = 0;
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
3138,7 → 3767,7
out_resp->count_enum_blobs = enum_count;
}
 
if (property->flags & DRM_MODE_PROP_BLOB) {
if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
copied = 0;
blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
3202,10 → 3831,23
}
 
#if 0
/**
* drm_mode_getblob_ioctl - get the contents of a blob property value
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* This function retrieves the contents of a blob property. The value stored in
* an object's blob property is just a normal modeset object id.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_getblob_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_object *obj;
struct drm_mode_get_blob *out_resp = data;
struct drm_property_blob *blob;
int ret = 0;
3215,12 → 3857,11
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
if (!obj) {
blob = drm_property_blob_find(dev, out_resp->blob_id);
if (!blob) {
ret = -ENOENT;
goto done;
}
blob = obj_to_blob(obj);
 
if (out_resp->length == blob->length) {
blob_ptr = (void __user *)(unsigned long)out_resp->data;
3237,6 → 3878,36
}
#endif
 
int drm_mode_connector_set_path_property(struct drm_connector *connector,
char *path)
{
struct drm_device *dev = connector->dev;
int ret, size;
size = strlen(path) + 1;
 
connector->path_blob_ptr = drm_property_create_blob(connector->dev,
size, path);
if (!connector->path_blob_ptr)
return -EINVAL;
 
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.path_property,
connector->path_blob_ptr->base.id);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 
/**
* drm_mode_connector_update_edid_property - update the edid property of a connector
* @connector: drm connector
* @edid: new value of the edid property
*
* This function creates a new blob modeset object and assigns its id to the
* connector's edid property.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_connector_update_edid_property(struct drm_connector *connector,
struct edid *edid)
{
3243,6 → 3914,10
struct drm_device *dev = connector->dev;
int ret, size;
 
/* ignore requests to set edid when overridden */
if (connector->override_edid)
return 0;
 
if (connector->edid_blob_ptr)
drm_property_destroy_blob(dev, connector->edid_blob_ptr);
 
3320,6 → 3995,21
return ret;
}
 
/**
* drm_mode_getproperty_ioctl - get the current value of a object's property
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* This function retrieves the current value for an object's property. Compared
* to the connector specific ioctl this one is extended to also work on crtc and
* plane objects.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
3376,6 → 4066,22
return ret;
}
 
/**
* drm_mode_obj_set_property_ioctl - set the current value of an object's property
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* This function sets the current value for an object's property. It also calls
* into a driver's ->set_property callback to update the hardware state.
* Compared to the connector specific ioctl this one is extended to also work on
* crtc and plane objects.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
3436,6 → 4142,18
}
#endif
 
/**
* drm_mode_connector_attach_encoder - attach a connector to an encoder
* @connector: connector to attach
* @encoder: encoder to attach @connector to
*
* This function links up a connector to an encoder. Note that the routing
* restrictions between encoders and crtcs are exposed to userspace through the
* possible_clones and possible_crtcs bitmasks.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_connector_attach_encoder(struct drm_connector *connector,
struct drm_encoder *encoder)
{
3451,21 → 4169,18
}
EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
 
void drm_mode_connector_detach_encoder(struct drm_connector *connector,
struct drm_encoder *encoder)
{
int i;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == encoder->base.id) {
connector->encoder_ids[i] = 0;
if (connector->encoder == encoder)
connector->encoder = NULL;
break;
}
}
}
EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
 
/**
* drm_mode_crtc_set_gamma_size - set the gamma table size
* @crtc: CRTC to set the gamma table size for
* @gamma_size: size of the gamma table
*
* Drivers which support gamma tables should set this to the supported gamma
* table size when initializing the CRTC. Currently the drm core only supports a
* fixed gamma table size.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size)
{
3482,11 → 4197,24
EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
 
#if 0
/**
* drm_mode_gamma_set_ioctl - set the gamma table
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* Set the gamma table of a CRTC to the one passed in by the user. Userspace can
* inquire the required gamma table size through drm_mode_gamma_get_ioctl.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_crtc_lut *crtc_lut = data;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
void *r_base, *g_base, *b_base;
int size;
3496,12 → 4224,11
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
}
crtc = obj_to_crtc(obj);
 
if (crtc->funcs->gamma_set == NULL) {
ret = -ENOSYS;
3541,11 → 4268,25
 
}
 
/**
* drm_mode_gamma_get_ioctl - get the gamma table
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* Copy the current gamma table into the storage provided. This also provides
* the gamma table size the driver expects, which can be used to size the
* allocated storage.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_crtc_lut *crtc_lut = data;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
void *r_base, *g_base, *b_base;
int size;
3555,12 → 4296,11
return -EINVAL;
 
drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
}
crtc = obj_to_crtc(obj);
 
/* memcpy into gamma store */
if (crtc_lut->gamma_size != crtc->gamma_size) {
3594,6 → 4334,14
#endif
 
 
/**
* drm_mode_config_reset - call ->reset callbacks
* @dev: drm device
*
* This functions calls all the crtc's, encoder's and connector's ->reset
* callback. Drivers can use this in e.g. their driver load or resume code to
* reset hardware and software state.
*/
void drm_mode_config_reset(struct drm_device *dev)
{
struct drm_crtc *crtc;
3690,7 → 4438,7
* drm_format_num_planes - get the number of planes for format
* @format: pixel format (DRM_FORMAT_*)
*
* RETURNS:
* Returns:
* The number of planes used by the specified pixel format.
*/
int drm_format_num_planes(uint32_t format)
3725,7 → 4473,7
* @format: pixel format (DRM_FORMAT_*)
* @plane: plane index
*
* RETURNS:
* Returns:
* The bytes per pixel value for the specified plane.
*/
int drm_format_plane_cpp(uint32_t format, int plane)
3771,7 → 4519,7
* drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
* @format: pixel format (DRM_FORMAT_*)
*
* RETURNS:
* Returns:
* The horizontal chroma subsampling factor for the
* specified pixel format.
*/
3806,7 → 4554,7
* drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
* @format: pixel format (DRM_FORMAT_*)
*
* RETURNS:
* Returns:
* The vertical chroma subsampling factor for the
* specified pixel format.
*/
3842,6 → 4590,7
void drm_mode_config_init(struct drm_device *dev)
{
mutex_init(&dev->mode_config.mutex);
drm_modeset_lock_init(&dev->mode_config.connection_mutex);
mutex_init(&dev->mode_config.idr_mutex);
mutex_init(&dev->mode_config.fb_lock);
INIT_LIST_HEAD(&dev->mode_config.fb_list);
3856,6 → 4605,7
 
drm_modeset_lock_all(dev);
drm_mode_create_standard_connector_properties(dev);
drm_mode_create_standard_plane_properties(dev);
drm_modeset_unlock_all(dev);
 
/* Just to be sure */
3863,6 → 4613,21
dev->mode_config.num_connector = 0;
dev->mode_config.num_crtc = 0;
dev->mode_config.num_encoder = 0;
dev->mode_config.num_overlay_plane = 0;
dev->mode_config.num_total_plane = 0;
}
EXPORT_SYMBOL(drm_mode_config_init);
 
/**
* drm_mode_config_cleanup - free up DRM mode_config info
* @dev: DRM device
*
* Free up all the connectors and CRTCs associated with this DRM device, then
* free up the framebuffers and associated buffer objects.
*
* Note that since this /should/ happen single-threaded at driver/device
* teardown time, no locking is required. It's the driver's job to ensure that
* this guarantee actually holds true.
*
* FIXME: cleanup any dangling user buffer objects too
*/