summaryrefslogtreecommitdiff
path: root/linux-core/drm_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/drm_crtc.c')
-rw-r--r--linux-core/drm_crtc.c270
1 files changed, 123 insertions, 147 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index cd60f522..44268337 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -280,73 +280,79 @@ static struct drm_display_mode std_mode[] = {
*
* FIXME: take into account monitor limits
*/
-void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
+void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int maxY)
{
- struct drm_output *output;
+ struct drm_device *dev = output->dev;
struct drm_display_mode *mode, *t;
int ret;
//if (maxX == 0 || maxY == 0)
// TODO
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- /* set all modes to the unverified state */
- list_for_each_entry_safe(mode, t, &output->modes, head)
- mode->status = MODE_UNVERIFIED;
+ /* set all modes to the unverified state */
+ list_for_each_entry_safe(mode, t, &output->modes, head)
+ mode->status = MODE_UNVERIFIED;
- output->status = (*output->funcs->detect)(output);
-
- if (output->status == output_status_disconnected) {
- DRM_DEBUG("%s is disconnected\n", output->name);
- /* TODO set EDID to NULL */
- continue;
- }
-
- ret = (*output->funcs->get_modes)(output);
-
- if (ret) {
- drm_mode_output_list_update(output);
- }
-
- if (maxX && maxY)
- drm_mode_validate_size(dev, &output->modes, maxX,
- maxY, 0);
- list_for_each_entry_safe(mode, t, &output->modes, head) {
- if (mode->status == MODE_OK)
- mode->status = (*output->funcs->mode_valid)(output,mode);
- }
+ output->status = (*output->funcs->detect)(output);
+
+ if (output->status == output_status_disconnected) {
+ DRM_DEBUG("%s is disconnected\n", output->name);
+ /* TODO set EDID to NULL */
+ return;
+ }
+
+ ret = (*output->funcs->get_modes)(output);
+
+ if (ret) {
+ drm_mode_output_list_update(output);
+ }
+
+ if (maxX && maxY)
+ drm_mode_validate_size(dev, &output->modes, maxX,
+ maxY, 0);
+ list_for_each_entry_safe(mode, t, &output->modes, head) {
+ if (mode->status == MODE_OK)
+ mode->status = (*output->funcs->mode_valid)(output,mode);
+ }
+
+
+ drm_mode_prune_invalid(dev, &output->modes, TRUE);
+
+ if (list_empty(&output->modes)) {
+ struct drm_display_mode *stdmode;
+ DRM_DEBUG("No valid modes on %s\n", output->name);
+
+ /* Should we do this here ???
+ * When no valid EDID modes are available we end up
+ * here and bailed in the past, now we add a standard
+ * 640x480@60Hz mode and carry on.
+ */
+ stdmode = drm_mode_duplicate(dev, &std_mode[0]);
+ drm_mode_probed_add(output, stdmode);
+ drm_mode_list_concat(&output->probed_modes,
+ &output->modes);
+
+ DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
+ output->name);
+ }
+
+ drm_mode_sort(&output->modes);
+
+ DRM_DEBUG("Probed modes for %s\n", output->name);
+ list_for_each_entry_safe(mode, t, &output->modes, head) {
+ mode->vrefresh = drm_mode_vrefresh(mode);
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_debug_printmodeline(dev, mode);
+ }
+}
- drm_mode_prune_invalid(dev, &output->modes, TRUE);
-
- if (list_empty(&output->modes)) {
- struct drm_display_mode *stdmode;
-
- DRM_DEBUG("No valid modes on %s\n", output->name);
-
- /* Should we do this here ???
- * When no valid EDID modes are available we end up
- * here and bailed in the past, now we add a standard
- * 640x480@60Hz mode and carry on.
- */
- stdmode = drm_mode_duplicate(dev, &std_mode[0]);
- drm_mode_probed_add(output, stdmode);
- drm_mode_list_concat(&output->probed_modes,
- &output->modes);
-
- DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
- output->name);
- }
-
- drm_mode_sort(&output->modes);
-
- DRM_DEBUG("Probed modes for %s\n", output->name);
- list_for_each_entry_safe(mode, t, &output->modes, head) {
- mode->vrefresh = drm_mode_vrefresh(mode);
+void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
+{
+ struct drm_output *output;
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
- drm_mode_debug_printmodeline(dev, mode);
- }
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ drm_crtc_probe_single_output_modes(output, maxX, maxY);
}
}
@@ -1068,8 +1074,6 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info,
*/
void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in)
{
-
- out->id = in->mode_id;
out->clock = in->clock;
out->hdisplay = in->hdisplay;
out->hsync_start = in->hsync_start;
@@ -1145,17 +1149,12 @@ int drm_mode_getresources(struct drm_device *dev,
struct drm_framebuffer *fb;
struct drm_output *output;
struct drm_crtc *crtc;
- struct drm_mode_modeinfo u_mode;
- struct drm_display_mode *mode;
int ret = 0;
- int mode_count= 0;
int output_count = 0;
int crtc_count = 0;
int fb_count = 0;
int copied = 0;
- memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
-
mutex_lock(&dev->mode_config.mutex);
list_for_each(lh, &dev->mode_config.fb_list)
@@ -1164,34 +1163,18 @@ int drm_mode_getresources(struct drm_device *dev,
list_for_each(lh, &dev->mode_config.crtc_list)
crtc_count++;
- list_for_each_entry(output, &dev->mode_config.output_list,
- head) {
+ list_for_each(lh, &dev->mode_config.output_list)
output_count++;
- list_for_each(lh, &output->modes)
- mode_count++;
- }
- list_for_each(lh, &dev->mode_config.usermode_list)
- mode_count++;
-
- if (card_res->count_modes == 0) {
- DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height);
- drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height);
- mode_count = 0;
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
- list_for_each(lh, &output->modes)
- mode_count++;
- }
- list_for_each(lh, &dev->mode_config.usermode_list)
- mode_count++;
- }
/* handle this in 4 parts */
/* FBs */
if (card_res->count_fbs >= fb_count) {
copied = 0;
list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
- if (put_user(fb->id, card_res->fb_id + copied))
- return -EFAULT;
+ if (put_user(fb->id, card_res->fb_id + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
copied++;
}
}
@@ -1202,8 +1185,10 @@ int drm_mode_getresources(struct drm_device *dev,
copied = 0;
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))
- return -EFAULT;
+ if (put_user(crtc->id, card_res->crtc_id + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
copied++;
}
}
@@ -1216,41 +1201,20 @@ int drm_mode_getresources(struct drm_device *dev,
list_for_each_entry(output, &dev->mode_config.output_list,
head) {
DRM_DEBUG("OUTPUT ID is %d\n", output->id);
- if (put_user(output->id, card_res->output_id + copied))
- return -EFAULT;
+ if (put_user(output->id, card_res->output_id + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
copied++;
}
}
card_res->count_outputs = output_count;
- /* Modes */
- if (card_res->count_modes >= mode_count) {
- copied = 0;
- list_for_each_entry(output, &dev->mode_config.output_list,
- head) {
- 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(u_mode)))
- return -EFAULT;
- copied++;
- }
- }
- /* add in user modes */
- 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(u_mode)))
- return -EFAULT;
- copied++;
- }
- }
- card_res->count_modes = mode_count;
+ DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs,
+ card_res->count_outputs);
- DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs,
- card_res->count_outputs,
- card_res->count_modes);
-
+
+out:
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
@@ -1299,14 +1263,16 @@ int drm_mode_getcrtc(struct drm_device *dev,
crtc_resp->outputs = 0;
if (crtc->enabled) {
- crtc_resp->mode = crtc->mode.mode_id;
+ drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+ crtc_resp->mode_valid = 1;
ocount = 0;
list_for_each_entry(output, &dev->mode_config.output_list, head) {
if (output->crtc == crtc)
crtc_resp->outputs |= 1 << (ocount++);
}
+
} else {
- crtc_resp->mode = 0;
+ crtc_resp->mode_valid = 0;
}
out:
@@ -1342,6 +1308,9 @@ int drm_mode_getoutput(struct drm_device *dev,
int ret = 0;
int copied = 0;
int i;
+ struct drm_mode_modeinfo u_mode;
+
+ memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
DRM_DEBUG("output id %d:\n", out_resp->output);
@@ -1365,6 +1334,10 @@ int drm_mode_getoutput(struct drm_device *dev,
}
}
+ if (out_resp->count_modes == 0) {
+ drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height);
+ }
+
strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN);
out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0;
@@ -1383,12 +1356,26 @@ int drm_mode_getoutput(struct drm_device *dev,
if ((out_resp->count_modes >= mode_count) && mode_count) {
copied = 0;
list_for_each_entry(mode, &output->modes, head) {
- out_resp->modes[copied++] = mode->mode_id;
+ drm_crtc_convert_to_umode(&u_mode, mode);
+ if (copy_to_user(out_resp->modes + copied,
+ &u_mode, sizeof(u_mode))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ copied++;
+
}
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))
- return -EFAULT;
+ if (!output->user_mode_ids[i])
+ continue;
+ mode = idr_find(&dev->mode_config.crtc_idr, output->user_mode_ids[i]);
+ if (mode && (mode->mode_id == output->user_mode_ids[i])) {
+ drm_crtc_convert_to_umode(&u_mode, mode);
+ if (copy_to_user(out_resp->modes + copied,
+ &u_mode, sizeof(u_mode))) {
+ ret = -EFAULT;
+ goto out;
+ }
copied++;
}
}
@@ -1442,8 +1429,9 @@ int drm_mode_setcrtc(struct drm_device *dev,
struct drm_mode_crtc *crtc_req = data;
struct drm_crtc *crtc;
struct drm_output **output_set = NULL, *output;
- struct drm_display_mode *mode;
struct drm_framebuffer *fb = NULL;
+ struct drm_display_mode mode;
+ int mode_valid = 0;
int ret = 0;
int i;
@@ -1455,7 +1443,7 @@ int drm_mode_setcrtc(struct drm_device *dev,
goto out;
}
- if (crtc_req->mode) {
+ if (crtc_req->mode_valid) {
/* 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);
@@ -1465,34 +1453,19 @@ int drm_mode_setcrtc(struct drm_device *dev,
goto out;
}
}
- mode = idr_find(&dev->mode_config.crtc_idr, crtc_req->mode);
- if (!mode || (mode->mode_id != crtc_req->mode)) {
- struct drm_output *output;
-
- list_for_each_entry(output,
- &dev->mode_config.output_list,
- head) {
- list_for_each_entry(mode, &output->modes,
- head) {
- drm_mode_debug_printmodeline(dev,
- mode);
- }
- }
- DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req->mode, mode);
- ret = -EINVAL;
- goto out;
- }
+ mode_valid = 1;
+ drm_crtc_convert_umode(&mode, &crtc_req->mode);
} else
- mode = NULL;
+ mode_valid = 0;
- if (crtc_req->count_outputs == 0 && mode) {
+ if (crtc_req->count_outputs == 0 && mode_valid) {
DRM_DEBUG("Count outputs is 0 but mode set\n");
ret = -EINVAL;
goto out;
}
- if (crtc_req->count_outputs > 0 && !mode && !fb) {
+ if (crtc_req->count_outputs > 0 && !mode_valid && !fb) {
DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs);
ret = -EINVAL;
goto out;
@@ -1523,8 +1496,12 @@ int drm_mode_setcrtc(struct drm_device *dev,
output_set[i] = output;
}
}
-
- ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb);
+
+ if (mode_valid) {
+ ret = drm_crtc_set_config(crtc, crtc_req, &mode, output_set, fb);
+ } else {
+ ret = drm_crtc_set_config(crtc, crtc_req, NULL, output_set, fb);
+ }
out:
mutex_unlock(&dev->mode_config.mutex);
@@ -1855,7 +1832,6 @@ int drm_mode_addmode_ioctl(struct drm_device *dev,
drm_crtc_convert_umode(user_mode, new_mode);
drm_mode_addmode(dev, user_mode);
- new_mode->id = user_mode->mode_id;
out:
mutex_unlock(&dev->mode_config.mutex);