[PATCH 8/8] modesetting: Add output hotplug support
Daniel Martin
consume.noise at gmail.com
Mon Dec 1 23:47:13 PST 2014
On Fri, Nov 28, 2014 at 11:20:53AM +0100, Daniel Martin wrote:
> From: Daniel Martin <consume.noise at gmail.com>
>
> When receiving a hotplug uevent, check if we have to add or remove
> outputs and act accordingly.
>
> Signed-off-by: Daniel Martin <consume.noise at gmail.com>
> ---
> With this patch we create or destroy outputs as a reaction to uevents.
>
> Due to my limited experience, the solution is either total crap, cause
> I'm doing it wrong, or it is that complicated, cause the server never
> had disappearing outputs in mind, or a combination of both.
>
> hw/xfree86/drivers/modesetting/drmmode_display.c | 150 ++++++++++++++++++++++-
> 1 file changed, 148 insertions(+), 2 deletions(-)
>
> diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
> index 474e5b6..876af68 100644
> --- a/hw/xfree86/drivers/modesetting/drmmode_display.c
> +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
> @@ -43,6 +43,7 @@
> #include "xf86Crtc.h"
> #include "drmmode_display.h"
>
> +#include <xf86RandR12.h>
> #include <cursorstr.h>
>
> #include <X11/extensions/dpmsconst.h>
> @@ -785,8 +786,10 @@ drmmode_output_destroy(xf86OutputPtr output)
> free(drmmode_output->props[i].atoms);
> }
> free(drmmode_output->props);
> - for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
> - drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
> + if (drmmode_output->mode_output) {
> + for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
> + drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
> + }
I'll split this hunk off into a distinct patch and attach the trace to
express why it is necessary.
> }
> free(drmmode_output->mode_encoders);
> drmModeFreeConnector(drmmode_output->mode_output);
> @@ -1488,12 +1491,155 @@ drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
> }
>
> #ifdef CONFIG_UDEV_KMS
> +static Bool
> +drmmode_output_add(drmmode_ptr drmmode, int nth_connector)
> +{
> + ScrnInfoPtr scrn = drmmode->scrn;
> + xf86OutputPtr output = drmmode_output_init(scrn, drmmode, nth_connector);
> +
> + xf86DrvMsg(scrn->scrnIndex, X_INFO, "Adding output %s\n", output->name);
Possible NULL dereference, move this below the following check.
> + if (!output)
> + return FALSE;
> +
> + output->randr_output = RROutputCreate(scrn->pScreen, output->name,
> + strlen(output->name), output);
> + if (!output->randr_output) {
> + xf86OutputDestroy(output);
> + return FALSE;
> + }
> +
> + drmmode_output_create_resources(output);
> + RRPostPendingProperties(output->randr_output);
> +
> + return TRUE;
> +}
> +
> +static Bool
> +drmmode_output_del(xf86OutputPtr output)
> +{
> + ScrnInfoPtr scrn = output->scrn;
> + rrScrPrivPtr pScrPriv = rrGetScrPriv(scrn->pScreen);
> + int i, j;
> +
> + output->funcs->dpms(output, DPMSModeOff);
> +
> + /* Remove the RROutput from RRCrtc, if any. */
> + if (output->randr_output->crtc) {
> + RRCrtcPtr rr_crtc = output->randr_output->crtc;
> +
> + if (rr_crtc->numOutputs < 2) {
> + RRCrtcSet(rr_crtc, NULL, 0, 0, 0, 0, NULL);
> + } else {
> + RROutputPtr *rr_outputs = calloc(rr_crtc->numOutputs,
> + sizeof(RROutputPtr));
> + if (!rr_outputs)
> + return FALSE;
> +
> + for (i = 0, j = 0; i < rr_crtc->numOutputs; i++) {
> + if (rr_crtc->outputs[i] != output->randr_output) {
> + rr_outputs[j] = rr_crtc->outputs[i];
> + }
> + j++;
> + }
> +
> + RRCrtcSet(rr_crtc, rr_crtc->mode, rr_crtc->x, rr_crtc->y,
> + rr_crtc->rotation, rr_crtc->numOutputs - 1, rr_outputs);
> + free(rr_outputs);
> + }
> + }
> +
> + /* Remove the RROutput from the list of available outputs. */
> + for (i = 0; i < pScrPriv->numOutputs; i++) {
> + if (pScrPriv->outputs[i] == output->randr_output) {
> + memmove(&pScrPriv->outputs[i], &pScrPriv->outputs[i + 1],
> + ((pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr)));
> + pScrPriv->numOutputs--;
> + break;
> + }
> + }
> +
> + xf86DrvMsg(scrn->scrnIndex, X_INFO, "Removing output %s\n", output->name);
> +
> + RROutputDestroy(output->randr_output);
> + output->randr_output = NULL;
> +
> + xf86OutputDestroy(output);
> +
> + return TRUE;
> +}
> +
> void
> drmmode_output_eval(drmmode_ptr drmmode)
> {
> ScrnInfoPtr scrn = drmmode->scrn;
> + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
> +
> + drmModeResPtr mode_res = NULL;
> +
> + int old_num_output = xf86_config->num_output;
> + xf86OutputPtr *output_del_list = NULL;
> +
> + Bool changed = FALSE;
> + int i, j;
> +
> + mode_res = drmModeGetResources(drmmode->fd);
> + if (mode_res) {
> + drmModeFreeResources(drmmode->mode_res);
> + drmmode->mode_res = mode_res;
> + } else
> + return;
> +
> + output_del_list = calloc(xf86_config->num_output + 1,
> + sizeof(*output_del_list));
> + if (!output_del_list)
> + goto out;
> +
> + /* Track all currently known outputs in output_del_list. We'll NULL each
> + * entry which we can match with one connector in mode_res->connectors.
> + * Later, every entry not being NULL is an output we have to delete. */
> + memcpy(output_del_list, xf86_config->output,
> + xf86_config->num_output * sizeof(*output_del_list));
> +
> + /* Check for outputs we already know or have to add. */
> + for (i = 0; i < mode_res->count_connectors; i++) {
> + Bool found = FALSE;
> +
> + for (j = 0; j < old_num_output; j++) {
> + drmmode_output_private_ptr drmmode_output;
> +
> + if (output_del_list[j] == NULL)
> + continue;
> +
> + drmmode_output = output_del_list[j]->driver_private;
> + if (drmmode_output->output_id == mode_res->connectors[i]) {
> + found = TRUE;
> + break;
> + }
> + }
> +
> + if (found)
> + /* Found the output, NULL the entry. */
> + output_del_list[j] = NULL;
> + else
> + changed |= drmmode_output_add(drmmode, i);
> + }
> +
> + for (i = 0; i < old_num_output; i++)
> + if (output_del_list[i] != NULL)
> + changed |= drmmode_output_del(output_del_list[i]);
> +
> + if (changed) {
> + xf86DisableUnusedFunctions(scrn);
> + drmmode_clones_init(scrn, drmmode);
> +
> + xf86RandR12TellChanged(xf86ScrnToScreen(scrn));
> + }
>
> RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
> +
> +out:
> + free(output_del_list);
> }
>
> static void
> --
> 2.1.3
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.x.org/archives/xorg-devel/attachments/20141202/cd019432/attachment-0001.sig>
More information about the xorg-devel
mailing list