[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