From 91cd3e3c097d581ea75ec4bcbc1ba8d23b471a2e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 28 Nov 2007 15:18:25 +1000 Subject: modesetting API change for removing mode ids and making modes per output. so really want to get a list of modes per output not the global hammer list. also we remove the mode ids and let the user pass back the full mode description need to fix up add/remove mode for user modes now --- linux-core/drm_crtc.c | 270 +++++++++++++++++++++++--------------------------- 1 file changed, 123 insertions(+), 147 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 96df9b11ad8974d7a2a0a589114cbbb04a584f18 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 13:42:32 +1000 Subject: finish of mode add/remove, just have attach/detach modes --- linux-core/drm_crtc.c | 202 ++++++++++---------------------------------------- linux-core/drm_crtc.h | 7 +- linux-core/drm_drv.c | 3 +- linux-core/intel_fb.c | 2 - 4 files changed, 41 insertions(+), 173 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 44268337..26aa5206 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -579,6 +579,7 @@ struct drm_output *drm_output_create(struct drm_device *dev, strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; output->subpixel_order = SubPixelUnknown; + INIT_LIST_HEAD(&output->user_modes); INIT_LIST_HEAD(&output->probed_modes); INIT_LIST_HEAD(&output->modes); /* randr_output? */ @@ -620,6 +621,9 @@ void drm_output_destroy(struct drm_output *output) list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); + list_for_each_entry_safe(mode, t, &output->user_modes, head) + drm_mode_remove(output, mode); + mutex_lock(&dev->mode_config.mutex); drm_idr_put(dev, output->id); list_del(&output->head); @@ -718,7 +722,6 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); INIT_LIST_HEAD(&dev->mode_config.property_list); - INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } EXPORT_SYMBOL(drm_mode_config_init); @@ -950,7 +953,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; - struct drm_display_mode *mode, *mt; struct drm_property *property, *pt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { @@ -961,10 +963,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_property_destroy(dev, property); } - list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { - drm_mode_destroy(dev, mode); - } - list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); @@ -1324,10 +1322,6 @@ int drm_mode_getoutput(struct drm_device *dev, list_for_each_entry(mode, &output->modes, head) mode_count++; - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) - if (output->user_mode_ids[i] != 0) - mode_count++; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { if (output->property_ids[i] != 0) { props_count++; @@ -1365,20 +1359,6 @@ int drm_mode_getoutput(struct drm_device *dev, copied++; } - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - 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++; - } - } } out_resp->count_modes = mode_count; @@ -1710,49 +1690,14 @@ void drm_fb_release(struct file *filp) /* * */ -void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode) -{ - user_mode->type |= DRM_MODE_TYPE_USERDEF; - - user_mode->output_count = 0; - list_add(&user_mode->head, &dev->mode_config.usermode_list); -} -EXPORT_SYMBOL(drm_mode_addmode); - -int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode) -{ - struct drm_display_mode *t; - int ret = -EINVAL; - list_for_each_entry(t, &dev->mode_config.usermode_list, head) { - if (t == mode) { - list_del(&mode->head); - drm_mode_destroy(dev, mode); - ret = 0; - break; - } - } - return ret; -} -EXPORT_SYMBOL(drm_mode_rmmode); static int drm_mode_attachmode(struct drm_device *dev, struct drm_output *output, struct drm_display_mode *mode) { int ret = 0; - int i; - - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == 0) { - output->user_mode_ids[i] = mode->mode_id; - mode->output_count++; - break; - } - } - - if (i == DRM_OUTPUT_MAX_UMODES) - ret = -ENOSPC; + list_add_tail(&mode->head, &output->user_modes); return ret; } @@ -1760,11 +1705,22 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_output *output; - + int ret = 0; + struct drm_display_mode *dup_mode; + int need_dup = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) - drm_mode_attachmode(dev, output, mode); + if (output->crtc == crtc) { + if (need_dup) + dup_mode = drm_mode_duplicate(dev, mode); + else + dup_mode = mode; + ret = drm_mode_attachmode(dev, output, dup_mode); + if (ret) + return ret; + need_dup = 1; + } } + return 0; } EXPORT_SYMBOL(drm_mode_attachmode_crtc); @@ -1773,13 +1729,15 @@ static int drm_mode_detachmode(struct drm_device *dev, struct drm_display_mode *mode) { int found = 0; - int ret = 0, i; + int ret = 0; + struct drm_display_mode *match_mode, *t; - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == mode->mode_id) { - output->user_mode_ids[i] = 0; - mode->output_count--; + list_for_each_entry_safe(match_mode, t, &output->user_modes, head) { + if (drm_mode_equal(match_mode, mode)) { + list_del(&match_mode->head); + drm_mode_destroy(dev, match_mode); found = 1; + break; } } @@ -1800,86 +1758,6 @@ int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mo } EXPORT_SYMBOL(drm_mode_detachmode_crtc); -/** - * drm_fb_addmode - adds a user defined mode - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * Adds a user specified mode to the kernel. - * - * Called by the user via ioctl. - * - * RETURNS: - * writes new mode id into arg. - * Zero on success, errno on failure. - */ -int drm_mode_addmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_modeinfo *new_mode = data; - struct drm_display_mode *user_mode; - int ret = 0; - - mutex_lock(&dev->mode_config.mutex); - user_mode = drm_mode_create(dev); - if (!user_mode) { - ret = -ENOMEM; - goto out; - } - - drm_crtc_convert_umode(user_mode, new_mode); - - drm_mode_addmode(dev, user_mode); - -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; -} - -/** - * drm_fb_rmmode - removes a user defined mode - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * Remove the user defined mode specified by the user. - * - * Called by the user via ioctl - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_rmmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - uint32_t *id = data; - struct drm_display_mode *mode; - int ret = -EINVAL; - - mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, *id); - if (!mode || (*id != mode->mode_id)) { - goto out; - } - - if (!(mode->type & DRM_MODE_TYPE_USERDEF)) { - goto out; - } - - if (mode->output_count) { - goto out; - } - - ret = drm_mode_rmmode(dev, mode); - -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; -} - /** * drm_fb_attachmode - Attach a user mode to an output * @inode: inode from the ioctl @@ -1899,21 +1777,24 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; + struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); - if (!mode || (mode->mode_id != mode_cmd->mode_id)) { + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); + if (!output || (output->id != mode_cmd->output_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)) { - ret = -EINVAL; + mode = drm_mode_create(dev); + if (!mode) { + ret = -ENOMEM; goto out; } + + drm_crtc_convert_umode(mode, umode); ret = drm_mode_attachmode(dev, output, mode); out: @@ -1939,25 +1820,20 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, { struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; - struct drm_display_mode *mode; + struct drm_display_mode mode; + struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); - 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)) { ret = -EINVAL; goto out; } - - - ret = drm_mode_detachmode(dev, output, mode); + + drm_crtc_convert_umode(&mode, umode); + ret = drm_mode_detachmode(dev, output, &mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 011903ce..90d6104f 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -448,7 +448,7 @@ struct drm_output { const struct drm_output_funcs *funcs; void *driver_private; - u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + struct list_head user_modes; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; @@ -484,8 +484,6 @@ struct drm_mode_config { int num_crtc; struct list_head crtc_list; - struct list_head usermode_list; - struct list_head property_list; int min_width, min_height; @@ -518,9 +516,6 @@ extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern void drm_disable_unused_functions(struct drm_device *dev); -extern void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode); -extern int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode); - /* for us by fb module */ extern int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b3e00e84..6a3e7041 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -124,8 +124,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDMODE, drm_mode_addmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 5f43f291..a8c9188d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -281,10 +281,8 @@ static int intelfb_set_par(struct fb_info *info) } if (!found) { - drm_mode_addmode(dev, drm_mode); if (par->fb_mode) { drm_mode_detachmode_crtc(dev, par->fb_mode); - drm_mode_rmmode(dev, par->fb_mode); } par->fb_mode = drm_mode; -- cgit v1.2.3 From 9a843d3bc79ae529f56e2f19e463b1b31c869a5b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:27:57 +1000 Subject: add flags to mode debug print --- linux-core/drm_modes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index fd00841e..3763ca69 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -46,12 +46,12 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { - DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", + DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->mode_id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type); + mode->vsync_end, mode->vtotal, mode->type, mode->flags); } EXPORT_SYMBOL(drm_mode_debug_printmodeline); -- cgit v1.2.3 From 1a07dd5ffd014aae8f767ab1f5166131aa27ef3f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:28:26 +1000 Subject: hooks up sync and flags and also clocks to get mode matching better --- linux-core/intel_fb.c | 52 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) (limited to 'linux-core') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index a8c9188d..0a3a00b5 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -216,6 +216,32 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return 0; } +bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) +{ + + if (mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1->vsync_start == mode2->vsync_start && + mode1->vsync_end == mode2->vsync_end && + mode1->vtotal == mode2->vtotal && + mode1->vscan == mode2->vscan && + mode1->flags == mode2->flags) + { + if (mode1->clock == mode2->clock) + return true; + + if (KHZ2PICOS(mode2->clock) == pixclock) + return true; + return false; + } + + return false; +} + /* this will let fbcon do the mode init */ /* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) @@ -260,6 +286,10 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); @@ -270,9 +300,8 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_debug_printmodeline(dev, drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name); drm_mode_debug_printmodeline(dev, search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { + if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; found = 1; @@ -550,7 +579,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.activate = FB_ACTIVATE_NOW; info->var.height = -1; info->var.width = -1; - info->var.vmode = FB_VMODE_NONINTERLACED; info->var.xres = mode->hdisplay; info->var.right_margin = mode->hsync_start - mode->hdisplay; @@ -560,10 +588,20 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.lower_margin = mode->vsync_start - mode->vdisplay; info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100; - /* avoid overflow */ - info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + info->var.pixclock = KHZ2PICOS(mode->clock); + + if (mode->flags & V_PHSYNC) + info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + + if (mode->flags & V_PVSYNC) + info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mode->flags & V_INTERLACE) + info->var.vmode = FB_VMODE_INTERLACED; + else if (mode->flags & V_DBLSCAN) + info->var.vmode = FB_VMODE_DOUBLE; + else + info->var.vmode = FB_VMODE_NONINTERLACED; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; -- cgit v1.2.3 From f7432d187e4b5e13c9e450bf12d5ab8c18ea5146 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 4 Dec 2007 14:38:00 -0800 Subject: Don't free driver mapped locks This fix is actually a bit of a cleanup too--it moves lock freeing to drm_rmmap_locked and out of drm_lastclose. This makes it symmetrical with addmap and also prevents the lock from being incorrectly freed from driver mappings. --- linux-core/drm_bufs.c | 2 ++ linux-core/drm_drv.c | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index bfd3dd3d..967e9a2d 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -413,6 +413,8 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) case _DRM_SHM: vfree(map->handle); dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.file_priv = NULL; + wake_up_interruptible(&dev->lock.lock_queue); break; case _DRM_AGP: case _DRM_SCATTER_GATHER: diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 6a3e7041..a88ae8b5 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -276,11 +276,6 @@ int drm_lastclose(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) drm_dma_takedown(dev); - if (dev->lock.hw_lock) { - dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.file_priv = NULL; - wake_up_interruptible(&dev->lock.lock_queue); - } dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 1a6c95ef711fce807659ab5e4fe480d65ac233b6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Dec 2007 16:03:05 +1000 Subject: arrgggh.. make all ioctl structs 32/64-bit compatible hopefully. This also starts to add blob property support. someone needs to check this work for other things like ppc/x86 alignment diffs --- linux-core/drm_crtc.c | 163 ++++++++++++++++++++++++++++++++++++------------- linux-core/drm_crtc.h | 23 +++++-- linux-core/intel_crt.c | 2 + 3 files changed, 140 insertions(+), 48 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 26aa5206..c2680319 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -722,7 +722,11 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); INIT_LIST_HEAD(&dev->mode_config.property_list); + INIT_LIST_HEAD(&dev->mode_config.property_blob_list); idr_init(&dev->mode_config.crtc_idr); + dev->mode_config.edid_property = drm_property_create(dev, + DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, + "EDID", 0); } EXPORT_SYMBOL(drm_mode_config_init); @@ -1013,7 +1017,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) changed = true; - if (new_mode && (crtc->mode.mode_id != new_mode->mode_id)) + if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) changed = true; list_for_each_entry(output, &dev->mode_config.output_list, head) { @@ -1152,6 +1156,9 @@ int drm_mode_getresources(struct drm_device *dev, int crtc_count = 0; int fb_count = 0; int copied = 0; + uint32_t __user *fb_id; + uint32_t __user *crtc_id; + uint32_t __user *output_id; mutex_lock(&dev->mode_config.mutex); @@ -1164,12 +1171,18 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.output_list) output_count++; + card_res->max_height = dev->mode_config.max_height; + card_res->min_height = dev->mode_config.min_height; + card_res->max_width = dev->mode_config.max_width; + card_res->min_width = dev->mode_config.min_width; + /* handle this in 4 parts */ /* FBs */ if (card_res->count_fbs >= fb_count) { copied = 0; + fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (put_user(fb->id, card_res->fb_id + copied)) { + if (put_user(fb->id, fb_id + copied)) { ret = -EFAULT; goto out; } @@ -1181,9 +1194,10 @@ int drm_mode_getresources(struct drm_device *dev, /* CRTCs */ if (card_res->count_crtcs >= crtc_count) { copied = 0; + crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr; 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)) { + if (put_user(crtc->id, crtc_id + copied)) { ret = -EFAULT; goto out; } @@ -1196,10 +1210,11 @@ int drm_mode_getresources(struct drm_device *dev, /* Outputs */ if (card_res->count_outputs >= output_count) { copied = 0; + output_id = (uint32_t *)(unsigned long)card_res->output_id_ptr; 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)) { + if (put_user(output->id, output_id + copied)) { ret = -EFAULT; goto out; } @@ -1211,7 +1226,6 @@ int drm_mode_getresources(struct drm_device *dev, DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs, card_res->count_outputs); - out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1307,6 +1321,9 @@ int drm_mode_getoutput(struct drm_device *dev, int copied = 0; int i; struct drm_mode_modeinfo u_mode; + struct drm_mode_modeinfo __user *mode_ptr; + uint32_t __user *prop_ptr; + uint64_t __user *prop_values; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); @@ -1349,9 +1366,10 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; + mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(out_resp->modes + copied, + if (copy_to_user(mode_ptr + copied, &u_mode, sizeof(u_mode))) { ret = -EFAULT; goto out; @@ -1364,14 +1382,16 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_props >= props_count) && props_count) { copied = 0; + prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr); + prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { if (output->property_ids[i] != 0) { - if (put_user(output->property_ids[i], out_resp->props + copied)) { + if (put_user(output->property_ids[i], prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(output->property_values[i], out_resp->prop_values + copied)) { + if (put_user(output->property_values[i], prop_values + copied)) { ret = -EFAULT; goto out; } @@ -1410,10 +1430,10 @@ int drm_mode_setcrtc(struct drm_device *dev, struct drm_crtc *crtc; struct drm_output **output_set = NULL, *output; struct drm_framebuffer *fb = NULL; - struct drm_display_mode mode; - int mode_valid = 0; + struct drm_display_mode *mode = NULL; int ret = 0; int i; + uint32_t __user *set_outputs_ptr; mutex_lock(&dev->mode_config.mutex); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); @@ -1434,18 +1454,17 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - mode_valid = 1; - drm_crtc_convert_umode(&mode, &crtc_req->mode); - } else - mode_valid = 0; + mode = drm_mode_create(dev); + drm_crtc_convert_umode(mode, &crtc_req->mode); + } - if (crtc_req->count_outputs == 0 && mode_valid) { + if (crtc_req->count_outputs == 0 && mode) { DRM_DEBUG("Count outputs is 0 but mode set\n"); ret = -EINVAL; goto out; } - if (crtc_req->count_outputs > 0 && !mode_valid && !fb) { + 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); ret = -EINVAL; goto out; @@ -1461,7 +1480,8 @@ int drm_mode_setcrtc(struct drm_device *dev, } for (i = 0; i < crtc_req->count_outputs; i++) { - if (get_user(out_id, &crtc_req->set_outputs[i])) { + set_outputs_ptr = (uint32_t *)(unsigned long)crtc_req->set_outputs_ptr; + if (get_user(out_id, &set_outputs_ptr[i])) { ret = -EFAULT; goto out; } @@ -1477,11 +1497,7 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - 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); - } + ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1847,15 +1863,17 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property = kzalloc(sizeof(struct drm_output), GFP_KERNEL); if (!property) return NULL; - - property->values = kzalloc(sizeof(uint32_t)*num_values, GFP_KERNEL); - if (!property->values) - goto fail; + + if (num_values) { + property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); + if (!property->values) + goto fail; + } property->id = drm_idr_get(dev, property); property->flags = flags; property->num_values = num_values; - INIT_LIST_HEAD(&property->enum_list); + INIT_LIST_HEAD(&property->enum_blob_list); if (name) strncpy(property->name, name, DRM_PROP_NAME_LEN); @@ -1869,15 +1887,15 @@ fail: EXPORT_SYMBOL(drm_property_create); int drm_property_add_enum(struct drm_property *property, int index, - uint32_t value, const char *name) + uint64_t value, const char *name) { struct drm_property_enum *prop_enum; if (!(property->flags & DRM_MODE_PROP_ENUM)) return -EINVAL; - if (!list_empty(&property->enum_list)) { - list_for_each_entry(prop_enum, &property->enum_list, head) { + if (!list_empty(&property->enum_blob_list)) { + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { if (prop_enum->value == value) { strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; @@ -1895,7 +1913,7 @@ int drm_property_add_enum(struct drm_property *property, int index, prop_enum->value = value; property->values[index] = value; - list_add_tail(&prop_enum->head, &property->enum_list); + list_add_tail(&prop_enum->head, &property->enum_blob_list); return 0; } EXPORT_SYMBOL(drm_property_add_enum); @@ -1904,12 +1922,13 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) { struct drm_property_enum *prop_enum, *pt; - list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { + list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { list_del(&prop_enum->head); kfree(prop_enum); } - kfree(property->values); + if (property->num_values) + kfree(property->values); drm_idr_put(dev, property->id); list_del(&property->head); kfree(property); @@ -1918,7 +1937,7 @@ EXPORT_SYMBOL(drm_property_destroy); int drm_output_attach_property(struct drm_output *output, - struct drm_property *property, int init_val) + struct drm_property *property, uint64_t init_val) { int i; @@ -1942,10 +1961,14 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_mode_get_property *out_resp = data; struct drm_property *property; int enum_count = 0; + int blob_count = 0; int value_count = 0; int ret = 0, i; int copied; struct drm_property_enum *prop_enum; + struct drm_property_enum __user *enum_ptr; + struct drm_property_blob *prop_blob; + uint64_t __user *values_ptr; mutex_lock(&dev->mode_config.mutex); property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); @@ -1954,9 +1977,13 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, goto done; } - - list_for_each_entry(prop_enum, &property->enum_list, head) - enum_count++; + if (property->flags & DRM_MODE_PROP_ENUM) { + list_for_each_entry(prop_enum, &property->enum_blob_list, head) + enum_count++; + } else if (property->flags & DRM_MODE_PROP_BLOB) { + list_for_each_entry(prop_blob, &property->enum_blob_list, head) + blob_count++; + } value_count = property->num_values; @@ -1965,8 +1992,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->flags = property->flags; if ((out_resp->count_values >= value_count) && value_count) { + values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr; for (i = 0; i < value_count; i++) { - if (put_user(property->values[i], out_resp->values + i)) { + if (put_user(property->values[i], values_ptr + i)) { ret = -EFAULT; goto done; } @@ -1974,10 +2002,30 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if ((out_resp->count_enums >= enum_count) && enum_count) { + if ((out_resp->count_enum_blobs >= enum_count) && enum_count && (property->flags & DRM_MODE_PROP_ENUM)) { + copied = 0; + enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { + if (put_user(prop_enum->value, &enum_ptr[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&enum_ptr[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { + ret = -EFAULT; + goto done; + } + copied++; + } + } + out_resp->count_enum_blobs = enum_count; + +#if 0 + if ((out_resp->count_blobs >= enum_count) && blob_count && (property->flags & DRM_MODE_PROP_BLOB)) { copied = 0; - list_for_each_entry(prop_enum, &property->enum_list, head) { - if (put_user(prop_enum->value, &out_resp->enums[copied].value)) { + list_for_each_entry(prop_blob, &property->enum_list, head) { + if (put_user(prop_enum->value, &out_resp->blobs[copied].value)) { ret = -EFAULT; goto done; } @@ -1991,8 +2039,39 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } } out_resp->count_enums = enum_count; - +#endif done: mutex_unlock(&dev->mode_config.mutex); return ret; } + +static int drm_property_create_blob(struct drm_device *dev, int length, + void *data) +{ + struct drm_property_blob *blob; + + if (!length || !data) + return -EINVAL; + + blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); + if (!blob) + return -EINVAL; + + blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); + blob->length = length; + + memcpy(blob->data, data, length); + + blob->id = drm_idr_get(dev, blob); + + list_add_tail(&blob->head, &dev->mode_config.property_blob_list); + return blob->id; +} + +static void drm_property_destroy_blob(struct drm_device *dev, + struct drm_property_blob *blob) +{ + drm_idr_put(dev, blob->id); + list_del(&blob->head); + kfree(blob); +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 90d6104f..d028f75f 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -234,9 +234,16 @@ struct drm_framebuffer { struct list_head filp_head; }; +struct drm_property_blob { + struct list_head head; + unsigned int id; + unsigned int length; + void *data; +}; + struct drm_property_enum { struct list_head head; - uint32_t value; + uint64_t value; unsigned char name[DRM_PROP_NAME_LEN]; }; @@ -246,9 +253,9 @@ struct drm_property { uint32_t flags; char name[DRM_PROP_NAME_LEN]; uint32_t num_values; - uint32_t *values; + uint64_t *values; - struct list_head enum_list; + struct list_head enum_blob_list; }; struct drm_crtc; @@ -451,7 +458,7 @@ struct drm_output { struct list_head user_modes; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; - u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; + uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; /** @@ -492,6 +499,10 @@ struct drm_mode_config { /* DGA stuff? */ struct drm_mode_config_funcs *funcs; unsigned long fb_base; + + /* pointers to standard properties */ + struct list_head property_blob_list; + struct drm_property *edid_property; }; struct drm_output *drm_output_create(struct drm_device *dev, @@ -549,12 +560,12 @@ extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo int x, int y); extern int drm_output_attach_property(struct drm_output *output, - struct drm_property *property, int init_val); + struct drm_property *property, uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, - uint32_t value, const char *name); + uint64_t value, const char *name); /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 29c2e611..d3ad4654 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -245,4 +245,6 @@ void intel_crt_init(struct drm_device *dev) output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; + + drm_output_attach_property(output, dev->mode_config.edid_property, 0); } -- cgit v1.2.3 From c9cda51af5a8bea1d30ce575ae260de52950fe2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Dec 2007 16:31:35 +1000 Subject: more WIP on blobs.. I'm going to pass back a list of blob ids and lengths in the getproperty. will need another ioctl to return the blob data as it is variable length. --- linux-core/drm_crtc.c | 67 ++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c2680319..a3aa783b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1968,7 +1968,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_property_enum *prop_enum; struct drm_property_enum __user *enum_ptr; struct drm_property_blob *prop_blob; + uint32_t *blob_id_ptr; uint64_t __user *values_ptr; + uint32_t __user *blob_length_ptr; mutex_lock(&dev->mode_config.mutex); property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); @@ -1980,7 +1982,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (property->flags & DRM_MODE_PROP_ENUM) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) enum_count++; - } else if (property->flags & DRM_MODE_PROP_BLOB) { + } else if (property->flags & DRM_MODE_PROP_BLOB) { list_for_each_entry(prop_blob, &property->enum_blob_list, head) blob_count++; } @@ -2002,44 +2004,49 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if ((out_resp->count_enum_blobs >= enum_count) && enum_count && (property->flags & DRM_MODE_PROP_ENUM)) { - copied = 0; - enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; - list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - if (put_user(prop_enum->value, &enum_ptr[copied].value)) { - ret = -EFAULT; - goto done; - } - - if (copy_to_user(&enum_ptr[copied].name, - prop_enum->name, DRM_PROP_NAME_LEN)) { + if (property->flags & DRM_MODE_PROP_ENUM) { + if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { + copied = 0; + enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { + if (put_user(prop_enum->value, &enum_ptr[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&enum_ptr[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; goto done; + } + copied++; } - copied++; } + out_resp->count_enum_blobs = enum_count; } - out_resp->count_enum_blobs = enum_count; -#if 0 - if ((out_resp->count_blobs >= enum_count) && blob_count && (property->flags & DRM_MODE_PROP_BLOB)) { - copied = 0; - list_for_each_entry(prop_blob, &property->enum_list, head) { - if (put_user(prop_enum->value, &out_resp->blobs[copied].value)) { - ret = -EFAULT; - goto done; - } - - if (copy_to_user(&out_resp->enums[copied].name, - prop_enum->name, DRM_PROP_NAME_LEN)) { - ret = -EFAULT; - goto done; + if (property->flags & DRM_MODE_PROP_BLOB) { + if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { + copied = 0; + blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; + blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; + + list_for_each_entry(prop_blob, &property->enum_blob_list, head) { + if (put_user(prop_blob->id, blob_id_ptr + copied)) { + ret = -EFAULT; + goto done; + } + + if (put_user(prop_blob->length, blob_length_ptr + copied)) { + ret = -EFAULT; + goto done; + } + + copied++; } - copied++; } + out_resp->count_enum_blobs = enum_count; } - out_resp->count_enums = enum_count; -#endif done: mutex_unlock(&dev->mode_config.mutex); return ret; -- cgit v1.2.3 From 67f6eb1eb8d3dc5bb5fdb097655d3da326f637c1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 10:44:51 +1000 Subject: add property blobs and edid reporting support --- linux-core/drm_crtc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++---- linux-core/drm_crtc.h | 8 ++++-- linux-core/drm_drv.c | 1 + linux-core/intel_crt.c | 1 - linux-core/intel_modes.c | 1 + 5 files changed, 76 insertions(+), 10 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a3aa783b..70844237 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -590,6 +590,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; + drm_output_attach_property(output, dev->mode_config.edid_property, 0); + mutex_unlock(&dev->mode_config.mutex); return output; @@ -1935,7 +1937,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) } EXPORT_SYMBOL(drm_property_destroy); - int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val) { @@ -1955,6 +1956,24 @@ int drm_output_attach_property(struct drm_output *output, } EXPORT_SYMBOL(drm_output_attach_property); +int drm_output_property_set_value(struct drm_output *output, + struct drm_property *property, uint64_t value) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == property->id) { + output->property_values[i] = value; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_property_set_value); + int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2052,17 +2071,17 @@ done: return ret; } -static int drm_property_create_blob(struct drm_device *dev, int length, - void *data) +static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, + void *data) { struct drm_property_blob *blob; if (!length || !data) - return -EINVAL; + return NULL; blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); if (!blob) - return -EINVAL; + return NULL; blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); blob->length = length; @@ -2072,7 +2091,7 @@ static int drm_property_create_blob(struct drm_device *dev, int length, blob->id = drm_idr_get(dev, blob); list_add_tail(&blob->head, &dev->mode_config.property_blob_list); - return blob->id; + return blob; } static void drm_property_destroy_blob(struct drm_device *dev, @@ -2082,3 +2101,47 @@ static void drm_property_destroy_blob(struct drm_device *dev, list_del(&blob->head); kfree(blob); } + +int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_blob *out_resp = data; + struct drm_property_blob *blob; + int ret = 0; + void *blob_ptr; + + mutex_lock(&dev->mode_config.mutex); + + blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id); + if (!blob || (blob->id != out_resp->blob_id)) { + ret = -EINVAL; + goto done; + } + + if (out_resp->length == blob->length) { + blob_ptr = (void *)(unsigned long)out_resp->data; + if (copy_to_user(blob_ptr, blob->data, blob->length)){ + ret = -EFAULT; + goto done; + } + } + out_resp->length = blob->length; + +done: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid) +{ + struct drm_device *dev = output->dev; + int ret = 0; + if (output->edid_blob_ptr) + drm_property_destroy_blob(dev, output->edid_blob_ptr); + + output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid); + + ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id); + return ret; +} +EXPORT_SYMBOL(drm_mode_output_update_edid_property); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d028f75f..2c77d9d7 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -236,8 +236,8 @@ struct drm_framebuffer { struct drm_property_blob { struct list_head head; - unsigned int id; unsigned int length; + unsigned int id; void *data; }; @@ -456,7 +456,7 @@ struct drm_output { void *driver_private; struct list_head user_modes; - + struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; @@ -547,7 +547,7 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern void drm_mode_output_list_update(struct drm_output *output); - +extern int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, @@ -594,5 +594,7 @@ extern int drm_mode_detachmode_ioctl(struct drm_device *dev, extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index a88ae8b5..f8665be7 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index d3ad4654..2ab6a27b 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -246,5 +246,4 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; - drm_output_attach_property(output, dev->mode_config.edid_property, 0); } diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 346cf1ac..f8bf496c 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -55,6 +55,7 @@ int intel_ddc_get_modes(struct drm_output *output) edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); if (edid) { + drm_mode_output_update_edid_property(output, edid); ret = drm_add_edid_modes(output, edid); kfree(edid); } -- cgit v1.2.3 From 1ba2bb3a7e77576333b09f296abac4c01c895c48 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:35:37 +1000 Subject: oops initialise variable to false --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 70844237..fba275b7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1005,7 +1005,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_device *dev = crtc->dev; struct drm_crtc **save_crtcs, *new_crtc; bool save_enabled = crtc->enabled; - bool changed; + bool changed = false; struct drm_output *output; int count = 0, ro; -- cgit v1.2.3 From 8020724615eb6f334d5f90b1e83e6a46d4a126ac Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:46:54 +1000 Subject: check previous mode first --- linux-core/intel_fb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 0a3a00b5..c81e4408 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -320,9 +320,11 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + if (par->crtc->enabled) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; - + } return 0; } -- cgit v1.2.3 From 9814e87016ff90556ae34e3395c10d29add2ba08 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:47:29 +1000 Subject: retab intelfb code --- linux-core/intel_fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index c81e4408..32c7dc31 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -321,9 +321,9 @@ static int intelfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) - return -EINVAL; + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; } return 0; } -- cgit v1.2.3