summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drm_crtc.c338
-rw-r--r--linux-core/drm_crtc.h1
-rw-r--r--linux-core/drm_fb.c9
-rw-r--r--linux-core/drm_modes.c2
-rw-r--r--linux-core/edid.h138
-rw-r--r--linux-core/intel_fb.c1
6 files changed, 202 insertions, 287 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index 1586eb1a..245fe5be 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -39,8 +39,7 @@
* @ptr: object pointer, used to generate unique ID
*
* LOCKING:
- * Process context (either init or calling process). Must take DRM mode_config
- * lock around IDR allocation.
+ * Caller must hold DRM mode_config lock.
*
* Create a unique identifier based on @ptr in @dev's identifier space. Used
* for tracking modes, CRTCs and outputs.
@@ -59,15 +58,12 @@ again:
return 0;
}
- spin_lock(&dev->mode_config.config_lock);
-
ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id);
if (ret == -EAGAIN) {
spin_unlock(&dev->mode_config.config_lock);
goto again;
}
- spin_unlock(&dev->mode_config.config_lock);
return new_id;
}
@@ -116,8 +112,7 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev,
* @dev: DRM device
*
* LOCKING:
- * Process context (either init or calling process). Must take DRM mode_config
- * lock around mode_config manipulation.
+ * Caller must hold mode config lock.
*
* Creates a new framebuffer objects and adds it to @dev's DRM mode_config.
*
@@ -128,27 +123,21 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev)
{
struct drm_framebuffer *fb;
- spin_lock(&dev->mode_config.config_lock);
/* Limit to single framebuffer for now */
if (dev->mode_config.num_fb > 1) {
spin_unlock(&dev->mode_config.config_lock);
DRM_ERROR("Attempt to add multiple framebuffers failed\n");
return NULL;
}
- spin_unlock(&dev->mode_config.config_lock);
fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL);
- if (!fb) {
-
+ if (!fb)
return NULL;
- }
fb->id = drm_idr_get(dev, fb);
fb->dev = dev;
- spin_lock(&dev->mode_config.config_lock);
dev->mode_config.num_fb++;
list_add(&fb->head, &dev->mode_config.fb_list);
- spin_unlock(&dev->mode_config.config_lock);
return fb;
}
@@ -159,8 +148,7 @@ EXPORT_SYMBOL(drm_framebuffer_create);
* @fb: framebuffer to remove
*
* LOCKING:
- * Process context (either init or calling process). Must take DRM mode_config
- * lock around mode_config manipulation.
+ * Caller must hold mode config lock.
*
* Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes
* it, setting it to NULL.
@@ -171,7 +159,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb)
struct drm_crtc *crtc;
/* remove from any CRTC */
- spin_lock(&dev->mode_config.config_lock);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb)
crtc->fb = NULL;
@@ -180,7 +167,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb)
drm_idr_put(dev, fb->id);
list_del(&fb->head);
dev->mode_config.num_fb--;
- spin_unlock(&dev->mode_config.config_lock);
kfree(fb);
}
@@ -192,8 +178,7 @@ EXPORT_SYMBOL(drm_framebuffer_destroy);
* @funcs: callbacks for the new CRTC
*
* LOCKING:
- * Process context (either init or calling process). Must take DRM mode_config
- * lock around mode_config manipulation.
+ * Caller must hold mode config lock.
*
* Creates a new CRTC object and adds it to @dev's mode_config structure.
*
@@ -214,10 +199,8 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev,
crtc->id = drm_idr_get(dev, crtc);
- spin_lock(&dev->mode_config.config_lock);
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
- spin_unlock(&dev->mode_config.config_lock);
return crtc;
}
@@ -228,8 +211,7 @@ EXPORT_SYMBOL(drm_crtc_create);
* @crtc: CRTC to remove
*
* LOCKING:
- * Process context (either init or calling process). Must take DRM mode_config
- * lock around mode_config traversal.
+ * Caller must hold mode config lock.
*
* Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from
* its associated DRM device's mode_config. Frees it afterwards.
@@ -241,11 +223,9 @@ void drm_crtc_destroy(struct drm_crtc *crtc)
if (crtc->funcs->cleanup)
(*crtc->funcs->cleanup)(crtc);
- spin_lock(&dev->mode_config.config_lock);
drm_idr_put(dev, crtc->id);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
- spin_unlock(&dev->mode_config.config_lock);
kfree(crtc);
}
EXPORT_SYMBOL(drm_crtc_destroy);
@@ -255,7 +235,7 @@ EXPORT_SYMBOL(drm_crtc_destroy);
* @crtc: CRTC to check
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* Walk @crtc's DRM device's mode_config and see if it's in use.
*
@@ -290,7 +270,7 @@ static struct drm_display_mode std_mode[] = {
* @maxY: max height for modes
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* Based on @dev's mode_config layout, scan all the outputs and try to detect
* modes on them. Modes will first be added to the output's probed_modes
@@ -380,7 +360,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
* @y: height of mode
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* Try to set @mode on @crtc. Give @crtc and its associated outputs a chance
* to fixup or reject the mode prior to trying to set it.
@@ -498,7 +478,7 @@ EXPORT_SYMBOL(drm_crtc_set_mode);
* @dev: DRM device
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* If an output or CRTC isn't part of @dev's mode_config, it can be disabled
* by calling its dpms function, which should power it off.
@@ -525,17 +505,14 @@ void drm_disable_unused_functions(struct drm_device *dev)
* @mode: mode data
*
* LOCKING:
- * Process context (either init or calling process). Must take @output's
- * mode_lock around mode list manipulation.
+ * Caller must hold mode config lock.
*
* Add @mode to @output's mode list for later use.
*/
void drm_mode_probed_add(struct drm_output *output,
struct drm_display_mode *mode)
{
- spin_lock(&output->modes_lock);
list_add(&mode->head, &output->probed_modes);
- spin_unlock(&output->modes_lock);
}
EXPORT_SYMBOL(drm_mode_probed_add);
@@ -545,16 +522,13 @@ EXPORT_SYMBOL(drm_mode_probed_add);
* @mode: mode to remove
*
* LOCKING:
- * Process context (either init or calling process). Must take @output's
- * mode_lock around mode list manipulation.
+ * Caller must hold mode config lock.
*
* Remove @mode from @output's mode list, then free it.
*/
void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode)
{
- spin_lock(&output->modes_lock);
list_del(&mode->head);
- spin_unlock(&output->modes_lock);
kfree(mode);
}
EXPORT_SYMBOL(drm_mode_remove);
@@ -566,8 +540,7 @@ EXPORT_SYMBOL(drm_mode_remove);
* @name: user visible name of the output
*
* LOCKING:
- * Process context (either init or calling process). Must take @dev's
- * mode_config lock around mode list manipulation.
+ * Caller must hold @dev's mode_config lock.
*
* Creates a new drm_output structure and adds it to @dev's mode_config
* structure.
@@ -594,7 +567,6 @@ struct drm_output *drm_output_create(drm_device_t *dev,
output->subpixel_order = SubPixelUnknown;
INIT_LIST_HEAD(&output->probed_modes);
INIT_LIST_HEAD(&output->modes);
- spin_lock_init(&output->modes_lock);
/* randr_output? */
/* output_set_monitor(output)? */
/* check for output_ignored(output)? */
@@ -615,9 +587,7 @@ EXPORT_SYMBOL(drm_output_create);
* @output: output to remove
*
* LOCKING:
- * Process context (either init or calling process). Must take @dev's
- * mode_config lock around mode list manipulation. Caller must hold
- * modes lock? (FIXME)
+ * Caller must hold @dev's mode_config lock.
*
* Call @output's cleanup function, then remove the output from the DRM
* mode_config after freeing @output's modes.
@@ -705,7 +675,7 @@ EXPORT_SYMBOL(drm_mode_create);
* @mode: mode to remove
*
* LOCKING:
- * None.
+ * Caller must hold mode config lock.
*
* Free @mode's unique identifier, then free it.
*/
@@ -787,7 +757,7 @@ out_err:
* @dev: DRM device
*
* LOCKING:
- * None.
+ * Caller must hold mode config lock.
*/
static void drm_pick_crtcs (drm_device_t *dev)
{
@@ -875,7 +845,7 @@ clone:
* @can_grow: this configuration is growable
*
* LOCKING:
- * Must take various locks. (FIXME)
+ * Called at init time, must take mode config lock.
*
* Scan the CRTCs and outputs and try to put together an initial setup.
* At the moment, this is a cloned configuration across all heads with
@@ -887,6 +857,9 @@ clone:
bool drm_initial_config(drm_device_t *dev, bool can_grow)
{
struct drm_output *output;
+ int ret = false;
+
+ spin_lock(&dev->mode_config.config_lock);
drm_crtc_probe_output_modes(dev, 2048, 2048);
@@ -902,7 +875,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)
}
drm_disable_unused_functions(dev);
- return false;
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
EXPORT_SYMBOL(drm_initial_config);
@@ -911,7 +885,7 @@ EXPORT_SYMBOL(drm_initial_config);
* @dev: DRM device
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* Free up all the outputs and CRTCs associated with this DRM device, then
* free up the framebuffers and associated buffer objects.
@@ -959,7 +933,7 @@ EXPORT_SYMBOL(drm_mode_config_cleanup);
* @fb: new framebuffer
*
* LOCKING:
- * Caller? (FIXME)
+ * Caller must hold mode config lock.
*
* Setup a new configuration, provided by the user in @crtc_info, and enable
* it.
@@ -1102,7 +1076,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Construct a set of configuration description structures and return
* them to the user, including CRTC, output and framebuffer configuration.
@@ -1125,7 +1099,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
struct drm_crtc *crtc;
struct drm_mode_modeinfo u_mode;
struct drm_display_mode *mode;
- int retcode = 0;
+ int ret = 0;
int mode_count= 0;
int output_count = 0;
int crtc_count = 0;
@@ -1134,6 +1108,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+ spin_lock(&dev->mode_config.config_lock);
+
list_for_each(lh, &dev->mode_config.fb_list)
fb_count++;
@@ -1149,8 +1125,10 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each(lh, &dev->mode_config.usermode_list)
mode_count++;
- if (copy_from_user(&card_res, argp, sizeof(card_res)))
- return -EFAULT;
+ if (copy_from_user(&card_res, argp, sizeof(card_res))) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
if (card_res.count_modes == 0) {
DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height);
@@ -1170,7 +1148,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
copied = 0;
list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
if (put_user(fb->id, &card_res.fb_id[copied++])) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1183,7 +1161,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){
DRM_DEBUG("CRTC ID is %d\n", crtc->id);
if (put_user(crtc->id, &card_res.crtc_id[copied++])) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1198,7 +1176,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
head) {
DRM_DEBUG("OUTPUT ID is %d\n", output->id);
if (put_user(output->id, &card_res.output_id[copied++])) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1213,7 +1191,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each_entry(mode, &output->modes, head) {
drm_crtc_convert_to_umode(&u_mode, mode);
if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1222,7 +1200,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each_entry(mode, &dev->mode_config.usermode_list, head) {
drm_crtc_convert_to_umode(&u_mode, mode);
if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1235,9 +1213,11 @@ done:
card_res.count_modes);
if (copy_to_user(argp, &card_res, sizeof(card_res)))
- return -EFAULT;
+ ret = -EFAULT;
- return retcode;
+out_unlock:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1267,14 +1247,18 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp,
struct drm_crtc *crtc;
struct drm_output *output;
int ocount;
- int retcode = 0;
+ int ret = 0;
if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id);
- if (!crtc || (crtc->id != crtc_resp.crtc_id))
- return -EINVAL;
+ if (!crtc || (crtc->id != crtc_resp.crtc_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
crtc_resp.x = crtc->x;
crtc_resp.y = crtc->y;
crtc_resp.fb_id = 1;
@@ -1293,9 +1277,11 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp,
}
if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp)))
- return -EFAULT;
+ ret = -EFAULT;
- return retcode;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1325,7 +1311,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
struct drm_output *output;
struct drm_display_mode *mode;
int mode_count = 0;
- int retcode = 0;
+ int ret = 0;
int copied = 0;
int i;
@@ -1333,9 +1319,13 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
return -EFAULT;
DRM_DEBUG("output id %d:\n", out_resp.output);
+
+ spin_lock(&dev->mode_config.config_lock);
output= idr_find(&dev->mode_config.crtc_idr, out_resp.output);
- if (!output || (output->id != out_resp.output))
- return -EINVAL;
+ if (!output || (output->id != out_resp.output)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
list_for_each_entry(mode, &output->modes, head)
mode_count++;
@@ -1360,14 +1350,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
copied = 0;
list_for_each_entry(mode, &output->modes, head) {
if (put_user(mode->mode_id, &out_resp.modes[copied++])) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
if (output->user_mode_ids[i] != 0)
if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) {
- retcode = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1377,9 +1367,11 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
done:
if (copy_to_user(argp, &out_resp, sizeof(out_resp)))
- return -EFAULT;
+ ret = -EFAULT;
- return retcode;
+out_unlock:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1410,26 +1402,28 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp,
struct drm_output **output_set = NULL, *output;
struct drm_display_mode *mode;
struct drm_framebuffer *fb = NULL;
- int retcode = 0;
+ int ret = 0;
int i;
if (copy_from_user(&crtc_req, argp, sizeof(crtc_req)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id);
if (!crtc || (crtc->id != crtc_req.crtc_id)) {
DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (crtc_req.mode) {
-
/* if we have a mode we need a framebuffer */
if (crtc_req.fb_id) {
fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id);
if (!fb || (fb->id != crtc_req.fb_id)) {
DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode);
@@ -1447,43 +1441,55 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp,
}
DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
} else
mode = NULL;
if (crtc_req.count_outputs == 0 && mode) {
DRM_DEBUG("Count outputs is 0 but mode set\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (crtc_req.count_outputs > 0 && !mode && !fb) {
DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req.count_outputs);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (crtc_req.count_outputs > 0) {
u32 out_id;
- output_set = kmalloc(crtc_req.count_outputs * sizeof(struct drm_output *), GFP_KERNEL);
- if (!output_set)
- return -ENOMEM;
+ output_set = kmalloc(crtc_req.count_outputs *
+ sizeof(struct drm_output *), GFP_KERNEL);
+ if (!output_set) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < crtc_req.count_outputs; i++) {
- if (get_user(out_id, &crtc_req.set_outputs[i]))
- return -EFAULT;
+ if (get_user(out_id, &crtc_req.set_outputs[i])) {
+ ret = -EFAULT;
+ goto out;
+ }
output = idr_find(&dev->mode_config.crtc_idr, out_id);
if (!output || (out_id != output->id)) {
DRM_DEBUG("Output id %d unknown\n", out_id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
output_set[i] = output;
}
}
- retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb);
- return retcode;
+ ret = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb);
+
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1494,7 +1500,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp,
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Add a new FB to the specified CRTC, given a user request.
*
@@ -1513,7 +1519,8 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
struct drm_mode_config *config = &dev->mode_config;
struct drm_framebuffer *fb;
struct drm_buffer_object *bo;
- int ret;
+ struct drm_crtc *crtc;
+ int ret = 0;
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
@@ -1527,17 +1534,22 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
return -EINVAL;
}
+ spin_lock(&dev->mode_config.config_lock);
/* TODO check limits are okay */
ret = drm_get_buffer_object(dev, &bo, r.handle);
- if (ret || !bo)
- return -EINVAL;
+ if (ret || !bo) {
+ ret = -EINVAL;
+ goto out;
+ }
/* TODO check buffer is sufficently large */
/* TODO setup destructor callback */
fb = drm_framebuffer_create(dev);
- if(!fb)
- return -EINVAL;;
+ if (!fb) {
+ ret = -EINVAL;
+ goto out;
+ }
fb->width = r.width;
fb->height = r.height;
@@ -1551,20 +1563,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
list_add(&fb->filp_head, &priv->fbs);
- if (copy_to_user(argp, &r, sizeof(r)))
- return -EFAULT;
+ if (copy_to_user(argp, &r, sizeof(r))) {
+ ret = -EFAULT;
+ goto out;
+ }
- /* bind the fb to the crtc for now */
- {
- struct drm_crtc *crtc;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- crtc->fb = fb;
-
- dev->driver->fb_probe(dev, crtc);
- }
+ /* FIXME: bind the fb to the right crtc */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ crtc->fb = fb;
+ dev->driver->fb_probe(dev, crtc);
}
- return 0;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1575,7 +1587,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Remove the FB specified by the user.
*
@@ -1591,12 +1603,15 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp,
drm_device_t *dev = priv->head->dev;
struct drm_framebuffer *fb = 0;
uint32_t id = arg;
+ int ret = 0;
+ spin_lock(&dev->mode_config.config_lock);
fb = idr_find(&dev->mode_config.crtc_idr, id);
/* TODO check that we realy get a framebuffer back. */
if (!fb || (id != fb->id)) {
DRM_ERROR("mode invalid framebuffer id\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
@@ -1608,7 +1623,9 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp,
drm_framebuffer_destroy(fb);
- return 0;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1636,14 +1653,17 @@ int drm_mode_getfb(struct inode *inode, struct file *filp,
struct drm_mode_fb_cmd __user *argp = (void __user *)arg;
struct drm_mode_fb_cmd r;
struct drm_framebuffer *fb;
+ int ret = 0;
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id);
if (!fb || (r.buffer_id != fb->id)) {
DRM_ERROR("invalid framebuffer id\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
r.height = fb->height;
@@ -1654,9 +1674,11 @@ int drm_mode_getfb(struct inode *inode, struct file *filp,
r.pitch = fb->pitch;
if (copy_to_user(argp, &r, sizeof(r)))
- return -EFAULT;
+ ret = -EFAULT;
- return 0;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1664,7 +1686,7 @@ int drm_mode_getfb(struct inode *inode, struct file *filp,
* @filp: file * from the ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Destroy all the FBs associated with @filp.
*
@@ -1679,11 +1701,13 @@ void drm_fb_release(struct file *filp)
drm_device_t *dev = priv->head->dev;
struct drm_framebuffer *fb, *tfb;
+ spin_lock(&dev->mode_config.config_lock);
list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
list_del(&fb->filp_head);
dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
drm_framebuffer_destroy(fb);
}
+ spin_unlock(&dev->mode_config.config_lock);
}
/**
@@ -1709,28 +1733,32 @@ int drm_mode_addmode(struct inode *inode, struct file *filp,
struct drm_mode_modeinfo __user *argp = (void __user *)arg;
struct drm_mode_modeinfo new_mode;
struct drm_display_mode *user_mode;
+ int ret = 0;
if (copy_from_user(&new_mode, argp, sizeof(new_mode)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
user_mode = drm_mode_create(dev);
- if (!user_mode)
- return -ENOMEM;
+ if (!user_mode) {
+ ret = -ENOMEM;
+ goto out;
+ }
drm_crtc_convert_umode(user_mode, &new_mode);
user_mode->type |= DRM_MODE_TYPE_USERDEF;
user_mode->output_count = 0;
- spin_lock(&dev->mode_config.config_lock);
list_add(&user_mode->head, &dev->mode_config.usermode_list);
- spin_unlock(&dev->mode_config.config_lock);
new_mode.id = user_mode->mode_id;
if (copy_to_user(argp, &new_mode, sizeof(new_mode)))
- return -EFAULT;
+ ret = -EFAULT;
- return 0;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
/**
@@ -1754,29 +1782,37 @@ int drm_mode_rmmode(struct inode *inode, struct file *filp,
drm_device_t *dev = priv->head->dev;
uint32_t id = arg;
struct drm_display_mode *mode, *t;
- int retcode = -EINVAL;
+ int ret = -EINVAL;
+ spin_lock(&dev->mode_config.config_lock);
mode = idr_find(&dev->mode_config.crtc_idr, id);
- if (!mode || (id != mode->mode_id))
- return -EINVAL;
+ if (!mode || (id != mode->mode_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
- if (!(mode->type & DRM_MODE_TYPE_USERDEF))
- return -EINVAL;
+ if (!(mode->type & DRM_MODE_TYPE_USERDEF)) {
+ ret = -EINVAL;
+ goto out;
+ }
- if (mode->output_count)
- return -EINVAL;
+ if (mode->output_count) {
+ ret = -EINVAL;
+ goto out;
+ }
- spin_lock(&dev->mode_config.config_lock);
list_for_each_entry(t, &dev->mode_config.usermode_list, head) {
if (t == mode) {
list_del(&mode->head);
drm_mode_destroy(dev, mode);
- retcode = 0;
+ ret = 0;
break;
}
}
+
+out:
spin_unlock(&dev->mode_config.config_lock);
- return retcode;
+ return ret;
}
/**
@@ -1801,18 +1837,24 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp,
struct drm_mode_mode_cmd mode_cmd;
struct drm_output *output;
struct drm_display_mode *mode;
- int i;
+ int i, ret = 0;
if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
+
mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id);
- if (!mode || (mode->mode_id != mode_cmd.mode_id))
- return -EINVAL;
+ if (!mode || (mode->mode_id != mode_cmd.mode_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id);
- if (!output || (output->id != mode_cmd.output_id))
- return -EINVAL;
+ if (!output || (output->id != mode_cmd.output_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
if (output->user_mode_ids[i] == 0) {
@@ -1823,9 +1865,11 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp,
}
if (i == DRM_OUTPUT_MAX_UMODES)
- return -ENOSPC;
+ ret = -ENOSPC;
- return 0;
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
@@ -1850,18 +1894,24 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp,
struct drm_mode_mode_cmd mode_cmd;
struct drm_output *output;
struct drm_display_mode *mode;
- int i, found = 0;
+ int i, found = 0, ret = 0;
if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd)))
return -EFAULT;
+ spin_lock(&dev->mode_config.config_lock);
+
mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id);
- if (!mode || (mode->mode_id != mode_cmd.mode_id))
- return -EINVAL;
+ if (!mode || (mode->mode_id != mode_cmd.mode_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id);
- if (!output || (output->id != mode_cmd.output_id))
- return -EINVAL;
+ if (!output || (output->id != mode_cmd.output_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
@@ -1873,7 +1923,9 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp,
}
if (!found)
- return -EINVAL;
-
- return 0;
+ ret = -EINVAL;
+
+out:
+ spin_unlock(&dev->mode_config.config_lock);
+ return ret;
}
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index 8dfd2e2b..e8a527b0 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -417,7 +417,6 @@ struct drm_output {
unsigned long possible_clones;
bool interlace_allowed;
bool doublescan_allowed;
- spinlock_t modes_lock; /* protects modes and probed_modes lists */
struct list_head modes; /* list of modes on this output */
/*
diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c
index 1531e96c..775fd180 100644
--- a/linux-core/drm_fb.c
+++ b/linux-core/drm_fb.c
@@ -300,9 +300,8 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
int ret;
info = framebuffer_alloc(sizeof(struct drmfb_par), device);
- if (!info){
- return -EINVAL;
- }
+ if (!info)
+ return -ENOMEM;
fb->fbdev = info;
@@ -409,8 +408,10 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
break;
}
- if (register_framebuffer(info) < 0)
+ if (register_framebuffer(info) < 0) {
+ unregister_framebuffer(info);
return -EINVAL;
+ }
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
info->fix.id);
diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c
index 97f7607d..41b5fade 100644
--- a/linux-core/drm_modes.c
+++ b/linux-core/drm_modes.c
@@ -141,7 +141,7 @@ EXPORT_SYMBOL(drm_mode_height);
*
* Return @mode's vrefresh rate or calculate it if necessary.
*
- * FIXME: why is this needed?
+ * FIXME: why is this needed? shouldn't vrefresh be set already?
*
* RETURNS:
* Vertical refresh rate of @mode x 1000. For precision reasons.
diff --git a/linux-core/edid.h b/linux-core/edid.h
deleted file mode 100644
index bd89fb3b..00000000
--- a/linux-core/edid.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * drivers/video/edid.h - EDID/DDC Header
- *
- * Based on:
- * 1. XFree86 4.3.0, edid.h
- * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- *
- * 2. John Fremlin <vii@users.sourceforge.net> and
- * Ani Joshi <ajoshi@unixbox.com>
- *
- * DDC is a Trademark of VESA (Video Electronics Standard Association).
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
-*/
-
-#ifndef __EDID_H__
-#define __EDID_H__
-
-#define EDID_LENGTH 0x80
-#define EDID_HEADER 0x00
-#define EDID_HEADER_END 0x07
-
-#define ID_MANUFACTURER_NAME 0x08
-#define ID_MANUFACTURER_NAME_END 0x09
-#define ID_MODEL 0x0a
-
-#define ID_SERIAL_NUMBER 0x0c
-
-#define MANUFACTURE_WEEK 0x10
-#define MANUFACTURE_YEAR 0x11
-
-#define EDID_STRUCT_VERSION 0x12
-#define EDID_STRUCT_REVISION 0x13
-
-#define EDID_STRUCT_DISPLAY 0x14
-
-#define DPMS_FLAGS 0x18
-#define ESTABLISHED_TIMING_1 0x23
-#define ESTABLISHED_TIMING_2 0x24
-#define MANUFACTURERS_TIMINGS 0x25
-
-/* standard timings supported */
-#define STD_TIMING 8
-#define STD_TIMING_DESCRIPTION_SIZE 2
-#define STD_TIMING_DESCRIPTIONS_START 0x26
-
-#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
-#define DETAILED_TIMING_DESCRIPTION_SIZE 18
-#define NO_DETAILED_TIMING_DESCRIPTIONS 4
-
-#define DETAILED_TIMING_DESCRIPTION_1 0x36
-#define DETAILED_TIMING_DESCRIPTION_2 0x48
-#define DETAILED_TIMING_DESCRIPTION_3 0x5a
-#define DETAILED_TIMING_DESCRIPTION_4 0x6c
-
-#define DESCRIPTOR_DATA 5
-
-#define UPPER_NIBBLE( x ) \
- (((128|64|32|16) & (x)) >> 4)
-
-#define LOWER_NIBBLE( x ) \
- ((1|2|4|8) & (x))
-
-#define COMBINE_HI_8LO( hi, lo ) \
- ( (((unsigned)hi) << 8) | (unsigned)lo )
-
-#define COMBINE_HI_4LO( hi, lo ) \
- ( (((unsigned)hi) << 4) | (unsigned)lo )
-
-#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
-#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
-#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000)
-#define H_ACTIVE_LO (unsigned)block[ 2 ]
-#define H_BLANKING_LO (unsigned)block[ 3 ]
-#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
-#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
-#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] )
-#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
-
-#define V_ACTIVE_LO (unsigned)block[ 5 ]
-#define V_BLANKING_LO (unsigned)block[ 6 ]
-#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] )
-#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
-#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] )
-#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
-
-#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ]
-#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ]
-
-#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] )
-#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] )
-
-#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2))
-#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2)
-
-#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4)
-#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6)
-
-#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
-#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
-
-#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
-#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
-
-#define H_SIZE_LO (unsigned)block[ 12 ]
-#define V_SIZE_LO (unsigned)block[ 13 ]
-
-#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] )
-#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] )
-
-#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
-#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
-
-#define H_BORDER (unsigned)block[ 15 ]
-#define V_BORDER (unsigned)block[ 16 ]
-
-#define FLAGS (unsigned)block[ 17 ]
-
-#define INTERLACED (FLAGS&128)
-#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */
-#define SYNC_SEPARATE (3<<3)
-#define HSYNC_POSITIVE (FLAGS & 4)
-#define VSYNC_POSITIVE (FLAGS & 2)
-
-#define V_MIN_RATE block[ 5 ]
-#define V_MAX_RATE block[ 6 ]
-#define H_MIN_RATE block[ 7 ]
-#define H_MAX_RATE block[ 8 ]
-#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10)
-#define GTF_SUPPORT block[10]
-
-#define DPMS_ACTIVE_OFF (1 << 5)
-#define DPMS_SUSPEND (1 << 6)
-#define DPMS_STANDBY (1 << 7)
-
-#endif /* __EDID_H__ */
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index ceeefc8c..449ef543 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -203,6 +203,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
}
/* this will let fbcon do the mode init */
+/* FIXME: take mode config lock? */
static int intelfb_set_par(struct fb_info *info)
{
struct intelfb_par *par = info->par;