diff options
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/drm_crtc.c | 270 | 
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);  | 
