linux/drivers/gpu/drm/gud/gud_connector.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright 2020 Noralf Trønnes
   4 */
   5
   6#include <linux/backlight.h>
   7#include <linux/workqueue.h>
   8
   9#include <drm/drm_atomic.h>
  10#include <drm/drm_atomic_state_helper.h>
  11#include <drm/drm_connector.h>
  12#include <drm/drm_drv.h>
  13#include <drm/drm_encoder.h>
  14#include <drm/drm_file.h>
  15#include <drm/drm_modeset_helper_vtables.h>
  16#include <drm/drm_print.h>
  17#include <drm/drm_probe_helper.h>
  18#include <drm/drm_simple_kms_helper.h>
  19#include <drm/gud.h>
  20
  21#include "gud_internal.h"
  22
  23struct gud_connector {
  24        struct drm_connector connector;
  25        struct drm_encoder encoder;
  26        struct backlight_device *backlight;
  27        struct work_struct backlight_work;
  28
  29        /* Supported properties */
  30        u16 *properties;
  31        unsigned int num_properties;
  32
  33        /* Initial gadget tv state if applicable, applied on state reset */
  34        struct drm_tv_connector_state initial_tv_state;
  35
  36        /*
  37         * Initial gadget backlight brightness if applicable, applied on state reset.
  38         * The value -ENODEV is used to signal no backlight.
  39         */
  40        int initial_brightness;
  41};
  42
  43static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
  44{
  45        return container_of(connector, struct gud_connector, connector);
  46}
  47
  48static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
  49{
  50        dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
  51}
  52
  53/*
  54 * Use a worker to avoid taking kms locks inside the backlight lock.
  55 * Other display drivers use backlight within their kms locks.
  56 * This avoids inconsistent locking rules, which would upset lockdep.
  57 */
  58static void gud_connector_backlight_update_status_work(struct work_struct *work)
  59{
  60        struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
  61        struct drm_connector *connector = &gconn->connector;
  62        struct drm_connector_state *connector_state;
  63        struct drm_device *drm = connector->dev;
  64        struct drm_modeset_acquire_ctx ctx;
  65        struct drm_atomic_state *state;
  66        int idx, ret;
  67
  68        if (!drm_dev_enter(drm, &idx))
  69                return;
  70
  71        state = drm_atomic_state_alloc(drm);
  72        if (!state) {
  73                ret = -ENOMEM;
  74                goto exit;
  75        }
  76
  77        drm_modeset_acquire_init(&ctx, 0);
  78        state->acquire_ctx = &ctx;
  79retry:
  80        connector_state = drm_atomic_get_connector_state(state, connector);
  81        if (IS_ERR(connector_state)) {
  82                ret = PTR_ERR(connector_state);
  83                goto out;
  84        }
  85
  86        /* Reuse tv.brightness to avoid having to subclass */
  87        connector_state->tv.brightness = gconn->backlight->props.brightness;
  88
  89        ret = drm_atomic_commit(state);
  90out:
  91        if (ret == -EDEADLK) {
  92                drm_atomic_state_clear(state);
  93                drm_modeset_backoff(&ctx);
  94                goto retry;
  95        }
  96
  97        drm_atomic_state_put(state);
  98
  99        drm_modeset_drop_locks(&ctx);
 100        drm_modeset_acquire_fini(&ctx);
 101exit:
 102        drm_dev_exit(idx);
 103
 104        if (ret)
 105                dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
 106}
 107
 108static int gud_connector_backlight_update_status(struct backlight_device *bd)
 109{
 110        struct drm_connector *connector = bl_get_data(bd);
 111        struct gud_connector *gconn = to_gud_connector(connector);
 112
 113        /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
 114        queue_work(system_long_wq, &gconn->backlight_work);
 115
 116        return 0;
 117}
 118
 119static const struct backlight_ops gud_connector_backlight_ops = {
 120        .update_status  = gud_connector_backlight_update_status,
 121};
 122
 123static int gud_connector_backlight_register(struct gud_connector *gconn)
 124{
 125        struct drm_connector *connector = &gconn->connector;
 126        struct backlight_device *bd;
 127        const char *name;
 128        const struct backlight_properties props = {
 129                .type = BACKLIGHT_RAW,
 130                .scale = BACKLIGHT_SCALE_NON_LINEAR,
 131                .max_brightness = 100,
 132                .brightness = gconn->initial_brightness,
 133        };
 134
 135        name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
 136                         connector->dev->primary->index, connector->name);
 137        if (!name)
 138                return -ENOMEM;
 139
 140        bd = backlight_device_register(name, connector->kdev, connector,
 141                                       &gud_connector_backlight_ops, &props);
 142        kfree(name);
 143        if (IS_ERR(bd))
 144                return PTR_ERR(bd);
 145
 146        gconn->backlight = bd;
 147
 148        return 0;
 149}
 150
 151static int gud_connector_detect(struct drm_connector *connector,
 152                                struct drm_modeset_acquire_ctx *ctx, bool force)
 153{
 154        struct gud_device *gdrm = to_gud_device(connector->dev);
 155        int idx, ret;
 156        u8 status;
 157
 158        if (!drm_dev_enter(connector->dev, &idx))
 159                return connector_status_disconnected;
 160
 161        if (force) {
 162                ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
 163                                  connector->index, NULL, 0);
 164                if (ret) {
 165                        ret = connector_status_unknown;
 166                        goto exit;
 167                }
 168        }
 169
 170        ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
 171        if (ret) {
 172                ret = connector_status_unknown;
 173                goto exit;
 174        }
 175
 176        switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
 177        case GUD_CONNECTOR_STATUS_DISCONNECTED:
 178                ret = connector_status_disconnected;
 179                break;
 180        case GUD_CONNECTOR_STATUS_CONNECTED:
 181                ret = connector_status_connected;
 182                break;
 183        default:
 184                ret = connector_status_unknown;
 185                break;
 186        }
 187
 188        if (status & GUD_CONNECTOR_STATUS_CHANGED)
 189                connector->epoch_counter += 1;
 190exit:
 191        drm_dev_exit(idx);
 192
 193        return ret;
 194}
 195
 196struct gud_connector_get_edid_ctx {
 197        void *buf;
 198        size_t len;
 199        bool edid_override;
 200};
 201
 202static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
 203{
 204        struct gud_connector_get_edid_ctx *ctx = data;
 205        size_t start = block * EDID_LENGTH;
 206
 207        ctx->edid_override = false;
 208
 209        if (start + len > ctx->len)
 210                return -1;
 211
 212        memcpy(buf, ctx->buf + start, len);
 213
 214        return 0;
 215}
 216
 217static int gud_connector_get_modes(struct drm_connector *connector)
 218{
 219        struct gud_device *gdrm = to_gud_device(connector->dev);
 220        struct gud_display_mode_req *reqmodes = NULL;
 221        struct gud_connector_get_edid_ctx edid_ctx;
 222        unsigned int i, num_modes = 0;
 223        struct edid *edid = NULL;
 224        int idx, ret;
 225
 226        if (!drm_dev_enter(connector->dev, &idx))
 227                return 0;
 228
 229        edid_ctx.edid_override = true;
 230        edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
 231        if (!edid_ctx.buf)
 232                goto out;
 233
 234        ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
 235                          edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
 236        if (ret > 0 && ret % EDID_LENGTH) {
 237                gud_conn_err(connector, "Invalid EDID size", ret);
 238        } else if (ret > 0) {
 239                edid_ctx.len = ret;
 240                edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
 241        }
 242
 243        kfree(edid_ctx.buf);
 244        drm_connector_update_edid_property(connector, edid);
 245
 246        if (edid && edid_ctx.edid_override)
 247                goto out;
 248
 249        reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
 250        if (!reqmodes)
 251                goto out;
 252
 253        ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
 254                          reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
 255        if (ret <= 0)
 256                goto out;
 257        if (ret % sizeof(*reqmodes)) {
 258                gud_conn_err(connector, "Invalid display mode array size", ret);
 259                goto out;
 260        }
 261
 262        num_modes = ret / sizeof(*reqmodes);
 263
 264        for (i = 0; i < num_modes; i++) {
 265                struct drm_display_mode *mode;
 266
 267                mode = drm_mode_create(connector->dev);
 268                if (!mode) {
 269                        num_modes = i;
 270                        goto out;
 271                }
 272
 273                gud_to_display_mode(mode, &reqmodes[i]);
 274                drm_mode_probed_add(connector, mode);
 275        }
 276out:
 277        if (!num_modes)
 278                num_modes = drm_add_edid_modes(connector, edid);
 279
 280        kfree(reqmodes);
 281        kfree(edid);
 282        drm_dev_exit(idx);
 283
 284        return num_modes;
 285}
 286
 287static int gud_connector_atomic_check(struct drm_connector *connector,
 288                                      struct drm_atomic_state *state)
 289{
 290        struct drm_connector_state *new_state;
 291        struct drm_crtc_state *new_crtc_state;
 292        struct drm_connector_state *old_state;
 293
 294        new_state = drm_atomic_get_new_connector_state(state, connector);
 295        if (!new_state->crtc)
 296                return 0;
 297
 298        old_state = drm_atomic_get_old_connector_state(state, connector);
 299        new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
 300
 301        if (old_state->tv.margins.left != new_state->tv.margins.left ||
 302            old_state->tv.margins.right != new_state->tv.margins.right ||
 303            old_state->tv.margins.top != new_state->tv.margins.top ||
 304            old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
 305            old_state->tv.mode != new_state->tv.mode ||
 306            old_state->tv.brightness != new_state->tv.brightness ||
 307            old_state->tv.contrast != new_state->tv.contrast ||
 308            old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
 309            old_state->tv.overscan != new_state->tv.overscan ||
 310            old_state->tv.saturation != new_state->tv.saturation ||
 311            old_state->tv.hue != new_state->tv.hue)
 312                new_crtc_state->connectors_changed = true;
 313
 314        return 0;
 315}
 316
 317static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
 318        .detect_ctx = gud_connector_detect,
 319        .get_modes = gud_connector_get_modes,
 320        .atomic_check = gud_connector_atomic_check,
 321};
 322
 323static int gud_connector_late_register(struct drm_connector *connector)
 324{
 325        struct gud_connector *gconn = to_gud_connector(connector);
 326
 327        if (gconn->initial_brightness < 0)
 328                return 0;
 329
 330        return gud_connector_backlight_register(gconn);
 331}
 332
 333static void gud_connector_early_unregister(struct drm_connector *connector)
 334{
 335        struct gud_connector *gconn = to_gud_connector(connector);
 336
 337        backlight_device_unregister(gconn->backlight);
 338        cancel_work_sync(&gconn->backlight_work);
 339}
 340
 341static void gud_connector_destroy(struct drm_connector *connector)
 342{
 343        struct gud_connector *gconn = to_gud_connector(connector);
 344
 345        drm_connector_cleanup(connector);
 346        kfree(gconn->properties);
 347        kfree(gconn);
 348}
 349
 350static void gud_connector_reset(struct drm_connector *connector)
 351{
 352        struct gud_connector *gconn = to_gud_connector(connector);
 353
 354        drm_atomic_helper_connector_reset(connector);
 355        connector->state->tv = gconn->initial_tv_state;
 356        /* Set margins from command line */
 357        drm_atomic_helper_connector_tv_reset(connector);
 358        if (gconn->initial_brightness >= 0)
 359                connector->state->tv.brightness = gconn->initial_brightness;
 360}
 361
 362static const struct drm_connector_funcs gud_connector_funcs = {
 363        .fill_modes = drm_helper_probe_single_connector_modes,
 364        .late_register = gud_connector_late_register,
 365        .early_unregister = gud_connector_early_unregister,
 366        .destroy = gud_connector_destroy,
 367        .reset = gud_connector_reset,
 368        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 369        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 370};
 371
 372/*
 373 * The tv.mode property is shared among the connectors and its enum names are
 374 * driver specific. This means that if more than one connector uses tv.mode,
 375 * the enum names has to be the same.
 376 */
 377static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
 378{
 379        size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
 380        const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
 381        unsigned int i, num_modes;
 382        char *buf;
 383        int ret;
 384
 385        buf = kmalloc(buf_len, GFP_KERNEL);
 386        if (!buf)
 387                return -ENOMEM;
 388
 389        ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
 390                          connector->index, buf, buf_len);
 391        if (ret < 0)
 392                goto free;
 393        if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
 394                ret = -EIO;
 395                goto free;
 396        }
 397
 398        num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
 399        for (i = 0; i < num_modes; i++)
 400                modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
 401
 402        ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
 403free:
 404        kfree(buf);
 405        if (ret < 0)
 406                gud_conn_err(connector, "Failed to add TV modes", ret);
 407
 408        return ret;
 409}
 410
 411static struct drm_property *
 412gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
 413{
 414        struct drm_mode_config *config = &connector->dev->mode_config;
 415
 416        switch (prop) {
 417        case GUD_PROPERTY_TV_LEFT_MARGIN:
 418                return config->tv_left_margin_property;
 419        case GUD_PROPERTY_TV_RIGHT_MARGIN:
 420                return config->tv_right_margin_property;
 421        case GUD_PROPERTY_TV_TOP_MARGIN:
 422                return config->tv_top_margin_property;
 423        case GUD_PROPERTY_TV_BOTTOM_MARGIN:
 424                return config->tv_bottom_margin_property;
 425        case GUD_PROPERTY_TV_MODE:
 426                return config->tv_mode_property;
 427        case GUD_PROPERTY_TV_BRIGHTNESS:
 428                return config->tv_brightness_property;
 429        case GUD_PROPERTY_TV_CONTRAST:
 430                return config->tv_contrast_property;
 431        case GUD_PROPERTY_TV_FLICKER_REDUCTION:
 432                return config->tv_flicker_reduction_property;
 433        case GUD_PROPERTY_TV_OVERSCAN:
 434                return config->tv_overscan_property;
 435        case GUD_PROPERTY_TV_SATURATION:
 436                return config->tv_saturation_property;
 437        case GUD_PROPERTY_TV_HUE:
 438                return config->tv_hue_property;
 439        default:
 440                return ERR_PTR(-EINVAL);
 441        }
 442}
 443
 444static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
 445{
 446        switch (prop) {
 447        case GUD_PROPERTY_TV_LEFT_MARGIN:
 448                return &state->margins.left;
 449        case GUD_PROPERTY_TV_RIGHT_MARGIN:
 450                return &state->margins.right;
 451        case GUD_PROPERTY_TV_TOP_MARGIN:
 452                return &state->margins.top;
 453        case GUD_PROPERTY_TV_BOTTOM_MARGIN:
 454                return &state->margins.bottom;
 455        case GUD_PROPERTY_TV_MODE:
 456                return &state->mode;
 457        case GUD_PROPERTY_TV_BRIGHTNESS:
 458                return &state->brightness;
 459        case GUD_PROPERTY_TV_CONTRAST:
 460                return &state->contrast;
 461        case GUD_PROPERTY_TV_FLICKER_REDUCTION:
 462                return &state->flicker_reduction;
 463        case GUD_PROPERTY_TV_OVERSCAN:
 464                return &state->overscan;
 465        case GUD_PROPERTY_TV_SATURATION:
 466                return &state->saturation;
 467        case GUD_PROPERTY_TV_HUE:
 468                return &state->hue;
 469        default:
 470                return ERR_PTR(-EINVAL);
 471        }
 472}
 473
 474static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
 475{
 476        struct drm_connector *connector = &gconn->connector;
 477        struct drm_device *drm = &gdrm->drm;
 478        struct gud_property_req *properties;
 479        unsigned int i, num_properties;
 480        int ret;
 481
 482        properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
 483        if (!properties)
 484                return -ENOMEM;
 485
 486        ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
 487                          properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
 488        if (ret <= 0)
 489                goto out;
 490        if (ret % sizeof(*properties)) {
 491                ret = -EIO;
 492                goto out;
 493        }
 494
 495        num_properties = ret / sizeof(*properties);
 496        ret = 0;
 497
 498        gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
 499        if (!gconn->properties) {
 500                ret = -ENOMEM;
 501                goto out;
 502        }
 503
 504        for (i = 0; i < num_properties; i++) {
 505                u16 prop = le16_to_cpu(properties[i].prop);
 506                u64 val = le64_to_cpu(properties[i].val);
 507                struct drm_property *property;
 508                unsigned int *state_val;
 509
 510                drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
 511
 512                switch (prop) {
 513                case GUD_PROPERTY_TV_LEFT_MARGIN:
 514                        fallthrough;
 515                case GUD_PROPERTY_TV_RIGHT_MARGIN:
 516                        fallthrough;
 517                case GUD_PROPERTY_TV_TOP_MARGIN:
 518                        fallthrough;
 519                case GUD_PROPERTY_TV_BOTTOM_MARGIN:
 520                        ret = drm_mode_create_tv_margin_properties(drm);
 521                        if (ret)
 522                                goto out;
 523                        break;
 524                case GUD_PROPERTY_TV_MODE:
 525                        ret = gud_connector_add_tv_mode(gdrm, connector);
 526                        if (ret)
 527                                goto out;
 528                        break;
 529                case GUD_PROPERTY_TV_BRIGHTNESS:
 530                        fallthrough;
 531                case GUD_PROPERTY_TV_CONTRAST:
 532                        fallthrough;
 533                case GUD_PROPERTY_TV_FLICKER_REDUCTION:
 534                        fallthrough;
 535                case GUD_PROPERTY_TV_OVERSCAN:
 536                        fallthrough;
 537                case GUD_PROPERTY_TV_SATURATION:
 538                        fallthrough;
 539                case GUD_PROPERTY_TV_HUE:
 540                        /* This is a no-op if already added. */
 541                        ret = drm_mode_create_tv_properties(drm, 0, NULL);
 542                        if (ret)
 543                                goto out;
 544                        break;
 545                case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
 546                        if (val > 100) {
 547                                ret = -EINVAL;
 548                                goto out;
 549                        }
 550                        gconn->initial_brightness = val;
 551                        break;
 552                default:
 553                        /* New ones might show up in future devices, skip those we don't know. */
 554                        drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
 555                        continue;
 556                }
 557
 558                gconn->properties[gconn->num_properties++] = prop;
 559
 560                if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
 561                        continue; /* not a DRM property */
 562
 563                property = gud_connector_property_lookup(connector, prop);
 564                if (WARN_ON(IS_ERR(property)))
 565                        continue;
 566
 567                state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
 568                if (WARN_ON(IS_ERR(state_val)))
 569                        continue;
 570
 571                *state_val = val;
 572                drm_object_attach_property(&connector->base, property, 0);
 573        }
 574out:
 575        kfree(properties);
 576
 577        return ret;
 578}
 579
 580int gud_connector_fill_properties(struct drm_connector_state *connector_state,
 581                                  struct gud_property_req *properties)
 582{
 583        struct gud_connector *gconn = to_gud_connector(connector_state->connector);
 584        unsigned int i;
 585
 586        for (i = 0; i < gconn->num_properties; i++) {
 587                u16 prop = gconn->properties[i];
 588                u64 val;
 589
 590                if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
 591                        val = connector_state->tv.brightness;
 592                } else {
 593                        unsigned int *state_val;
 594
 595                        state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
 596                        if (WARN_ON_ONCE(IS_ERR(state_val)))
 597                                return PTR_ERR(state_val);
 598
 599                        val = *state_val;
 600                }
 601
 602                properties[i].prop = cpu_to_le16(prop);
 603                properties[i].val = cpu_to_le64(val);
 604        }
 605
 606        return gconn->num_properties;
 607}
 608
 609static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
 610                                struct gud_connector_descriptor_req *desc)
 611{
 612        struct drm_device *drm = &gdrm->drm;
 613        struct gud_connector *gconn;
 614        struct drm_connector *connector;
 615        struct drm_encoder *encoder;
 616        int ret, connector_type;
 617        u32 flags;
 618
 619        gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
 620        if (!gconn)
 621                return -ENOMEM;
 622
 623        INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
 624        gconn->initial_brightness = -ENODEV;
 625        flags = le32_to_cpu(desc->flags);
 626        connector = &gconn->connector;
 627
 628        drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
 629
 630        switch (desc->connector_type) {
 631        case GUD_CONNECTOR_TYPE_PANEL:
 632                connector_type = DRM_MODE_CONNECTOR_USB;
 633                break;
 634        case GUD_CONNECTOR_TYPE_VGA:
 635                connector_type = DRM_MODE_CONNECTOR_VGA;
 636                break;
 637        case GUD_CONNECTOR_TYPE_DVI:
 638                connector_type = DRM_MODE_CONNECTOR_DVID;
 639                break;
 640        case GUD_CONNECTOR_TYPE_COMPOSITE:
 641                connector_type = DRM_MODE_CONNECTOR_Composite;
 642                break;
 643        case GUD_CONNECTOR_TYPE_SVIDEO:
 644                connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 645                break;
 646        case GUD_CONNECTOR_TYPE_COMPONENT:
 647                connector_type = DRM_MODE_CONNECTOR_Component;
 648                break;
 649        case GUD_CONNECTOR_TYPE_DISPLAYPORT:
 650                connector_type = DRM_MODE_CONNECTOR_DisplayPort;
 651                break;
 652        case GUD_CONNECTOR_TYPE_HDMI:
 653                connector_type = DRM_MODE_CONNECTOR_HDMIA;
 654                break;
 655        default: /* future types */
 656                connector_type = DRM_MODE_CONNECTOR_USB;
 657                break;
 658        }
 659
 660        drm_connector_helper_add(connector, &gud_connector_helper_funcs);
 661        ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
 662        if (ret) {
 663                kfree(connector);
 664                return ret;
 665        }
 666
 667        if (WARN_ON(connector->index != index))
 668                return -EINVAL;
 669
 670        if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
 671                connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
 672        if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
 673                connector->interlace_allowed = true;
 674        if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
 675                connector->doublescan_allowed = true;
 676
 677        ret = gud_connector_add_properties(gdrm, gconn);
 678        if (ret) {
 679                gud_conn_err(connector, "Failed to add properties", ret);
 680                return ret;
 681        }
 682
 683        /* The first connector is attached to the existing simple pipe encoder */
 684        if (!connector->index) {
 685                encoder = &gdrm->pipe.encoder;
 686        } else {
 687                encoder = &gconn->encoder;
 688
 689                ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
 690                if (ret)
 691                        return ret;
 692
 693                encoder->possible_crtcs = 1;
 694        }
 695
 696        return drm_connector_attach_encoder(connector, encoder);
 697}
 698
 699int gud_get_connectors(struct gud_device *gdrm)
 700{
 701        struct gud_connector_descriptor_req *descs;
 702        unsigned int i, num_connectors;
 703        int ret;
 704
 705        descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
 706        if (!descs)
 707                return -ENOMEM;
 708
 709        ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
 710                          descs, GUD_CONNECTORS_MAX_NUM * sizeof(*descs));
 711        if (ret < 0)
 712                goto free;
 713        if (!ret || ret % sizeof(*descs)) {
 714                ret = -EIO;
 715                goto free;
 716        }
 717
 718        num_connectors = ret / sizeof(*descs);
 719
 720        for (i = 0; i < num_connectors; i++) {
 721                ret = gud_connector_create(gdrm, i, &descs[i]);
 722                if (ret)
 723                        goto free;
 724        }
 725free:
 726        kfree(descs);
 727
 728        return ret;
 729}
 730