Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright 2020 Noralf Trønnes
0004  */
0005 
0006 #include <linux/backlight.h>
0007 #include <linux/workqueue.h>
0008 
0009 #include <drm/drm_atomic.h>
0010 #include <drm/drm_atomic_state_helper.h>
0011 #include <drm/drm_connector.h>
0012 #include <drm/drm_drv.h>
0013 #include <drm/drm_edid.h>
0014 #include <drm/drm_encoder.h>
0015 #include <drm/drm_file.h>
0016 #include <drm/drm_modeset_helper_vtables.h>
0017 #include <drm/drm_print.h>
0018 #include <drm/drm_probe_helper.h>
0019 #include <drm/drm_simple_kms_helper.h>
0020 #include <drm/gud.h>
0021 
0022 #include "gud_internal.h"
0023 
0024 struct gud_connector {
0025     struct drm_connector connector;
0026     struct drm_encoder encoder;
0027     struct backlight_device *backlight;
0028     struct work_struct backlight_work;
0029 
0030     /* Supported properties */
0031     u16 *properties;
0032     unsigned int num_properties;
0033 
0034     /* Initial gadget tv state if applicable, applied on state reset */
0035     struct drm_tv_connector_state initial_tv_state;
0036 
0037     /*
0038      * Initial gadget backlight brightness if applicable, applied on state reset.
0039      * The value -ENODEV is used to signal no backlight.
0040      */
0041     int initial_brightness;
0042 };
0043 
0044 static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
0045 {
0046     return container_of(connector, struct gud_connector, connector);
0047 }
0048 
0049 static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
0050 {
0051     dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
0052 }
0053 
0054 /*
0055  * Use a worker to avoid taking kms locks inside the backlight lock.
0056  * Other display drivers use backlight within their kms locks.
0057  * This avoids inconsistent locking rules, which would upset lockdep.
0058  */
0059 static void gud_connector_backlight_update_status_work(struct work_struct *work)
0060 {
0061     struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
0062     struct drm_connector *connector = &gconn->connector;
0063     struct drm_connector_state *connector_state;
0064     struct drm_device *drm = connector->dev;
0065     struct drm_modeset_acquire_ctx ctx;
0066     struct drm_atomic_state *state;
0067     int idx, ret;
0068 
0069     if (!drm_dev_enter(drm, &idx))
0070         return;
0071 
0072     state = drm_atomic_state_alloc(drm);
0073     if (!state) {
0074         ret = -ENOMEM;
0075         goto exit;
0076     }
0077 
0078     drm_modeset_acquire_init(&ctx, 0);
0079     state->acquire_ctx = &ctx;
0080 retry:
0081     connector_state = drm_atomic_get_connector_state(state, connector);
0082     if (IS_ERR(connector_state)) {
0083         ret = PTR_ERR(connector_state);
0084         goto out;
0085     }
0086 
0087     /* Reuse tv.brightness to avoid having to subclass */
0088     connector_state->tv.brightness = gconn->backlight->props.brightness;
0089 
0090     ret = drm_atomic_commit(state);
0091 out:
0092     if (ret == -EDEADLK) {
0093         drm_atomic_state_clear(state);
0094         drm_modeset_backoff(&ctx);
0095         goto retry;
0096     }
0097 
0098     drm_atomic_state_put(state);
0099 
0100     drm_modeset_drop_locks(&ctx);
0101     drm_modeset_acquire_fini(&ctx);
0102 exit:
0103     drm_dev_exit(idx);
0104 
0105     if (ret)
0106         dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
0107 }
0108 
0109 static int gud_connector_backlight_update_status(struct backlight_device *bd)
0110 {
0111     struct drm_connector *connector = bl_get_data(bd);
0112     struct gud_connector *gconn = to_gud_connector(connector);
0113 
0114     /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
0115     queue_work(system_long_wq, &gconn->backlight_work);
0116 
0117     return 0;
0118 }
0119 
0120 static const struct backlight_ops gud_connector_backlight_ops = {
0121     .update_status  = gud_connector_backlight_update_status,
0122 };
0123 
0124 static int gud_connector_backlight_register(struct gud_connector *gconn)
0125 {
0126     struct drm_connector *connector = &gconn->connector;
0127     struct backlight_device *bd;
0128     const char *name;
0129     const struct backlight_properties props = {
0130         .type = BACKLIGHT_RAW,
0131         .scale = BACKLIGHT_SCALE_NON_LINEAR,
0132         .max_brightness = 100,
0133         .brightness = gconn->initial_brightness,
0134     };
0135 
0136     name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
0137              connector->dev->primary->index, connector->name);
0138     if (!name)
0139         return -ENOMEM;
0140 
0141     bd = backlight_device_register(name, connector->kdev, connector,
0142                        &gud_connector_backlight_ops, &props);
0143     kfree(name);
0144     if (IS_ERR(bd))
0145         return PTR_ERR(bd);
0146 
0147     gconn->backlight = bd;
0148 
0149     return 0;
0150 }
0151 
0152 static int gud_connector_detect(struct drm_connector *connector,
0153                 struct drm_modeset_acquire_ctx *ctx, bool force)
0154 {
0155     struct gud_device *gdrm = to_gud_device(connector->dev);
0156     int idx, ret;
0157     u8 status;
0158 
0159     if (!drm_dev_enter(connector->dev, &idx))
0160         return connector_status_disconnected;
0161 
0162     if (force) {
0163         ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
0164                   connector->index, NULL, 0);
0165         if (ret) {
0166             ret = connector_status_unknown;
0167             goto exit;
0168         }
0169     }
0170 
0171     ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
0172     if (ret) {
0173         ret = connector_status_unknown;
0174         goto exit;
0175     }
0176 
0177     switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
0178     case GUD_CONNECTOR_STATUS_DISCONNECTED:
0179         ret = connector_status_disconnected;
0180         break;
0181     case GUD_CONNECTOR_STATUS_CONNECTED:
0182         ret = connector_status_connected;
0183         break;
0184     default:
0185         ret = connector_status_unknown;
0186         break;
0187     }
0188 
0189     if (status & GUD_CONNECTOR_STATUS_CHANGED)
0190         connector->epoch_counter += 1;
0191 exit:
0192     drm_dev_exit(idx);
0193 
0194     return ret;
0195 }
0196 
0197 struct gud_connector_get_edid_ctx {
0198     void *buf;
0199     size_t len;
0200     bool edid_override;
0201 };
0202 
0203 static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
0204 {
0205     struct gud_connector_get_edid_ctx *ctx = data;
0206     size_t start = block * EDID_LENGTH;
0207 
0208     ctx->edid_override = false;
0209 
0210     if (start + len > ctx->len)
0211         return -1;
0212 
0213     memcpy(buf, ctx->buf + start, len);
0214 
0215     return 0;
0216 }
0217 
0218 static int gud_connector_get_modes(struct drm_connector *connector)
0219 {
0220     struct gud_device *gdrm = to_gud_device(connector->dev);
0221     struct gud_display_mode_req *reqmodes = NULL;
0222     struct gud_connector_get_edid_ctx edid_ctx;
0223     unsigned int i, num_modes = 0;
0224     struct edid *edid = NULL;
0225     int idx, ret;
0226 
0227     if (!drm_dev_enter(connector->dev, &idx))
0228         return 0;
0229 
0230     edid_ctx.edid_override = true;
0231     edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
0232     if (!edid_ctx.buf)
0233         goto out;
0234 
0235     ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
0236               edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
0237     if (ret > 0 && ret % EDID_LENGTH) {
0238         gud_conn_err(connector, "Invalid EDID size", ret);
0239     } else if (ret > 0) {
0240         edid_ctx.len = ret;
0241         edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
0242     }
0243 
0244     kfree(edid_ctx.buf);
0245     drm_connector_update_edid_property(connector, edid);
0246 
0247     if (edid && edid_ctx.edid_override)
0248         goto out;
0249 
0250     reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
0251     if (!reqmodes)
0252         goto out;
0253 
0254     ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
0255               reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
0256     if (ret <= 0)
0257         goto out;
0258     if (ret % sizeof(*reqmodes)) {
0259         gud_conn_err(connector, "Invalid display mode array size", ret);
0260         goto out;
0261     }
0262 
0263     num_modes = ret / sizeof(*reqmodes);
0264 
0265     for (i = 0; i < num_modes; i++) {
0266         struct drm_display_mode *mode;
0267 
0268         mode = drm_mode_create(connector->dev);
0269         if (!mode) {
0270             num_modes = i;
0271             goto out;
0272         }
0273 
0274         gud_to_display_mode(mode, &reqmodes[i]);
0275         drm_mode_probed_add(connector, mode);
0276     }
0277 out:
0278     if (!num_modes)
0279         num_modes = drm_add_edid_modes(connector, edid);
0280 
0281     kfree(reqmodes);
0282     kfree(edid);
0283     drm_dev_exit(idx);
0284 
0285     return num_modes;
0286 }
0287 
0288 static int gud_connector_atomic_check(struct drm_connector *connector,
0289                       struct drm_atomic_state *state)
0290 {
0291     struct drm_connector_state *new_state;
0292     struct drm_crtc_state *new_crtc_state;
0293     struct drm_connector_state *old_state;
0294 
0295     new_state = drm_atomic_get_new_connector_state(state, connector);
0296     if (!new_state->crtc)
0297         return 0;
0298 
0299     old_state = drm_atomic_get_old_connector_state(state, connector);
0300     new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
0301 
0302     if (old_state->tv.margins.left != new_state->tv.margins.left ||
0303         old_state->tv.margins.right != new_state->tv.margins.right ||
0304         old_state->tv.margins.top != new_state->tv.margins.top ||
0305         old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
0306         old_state->tv.mode != new_state->tv.mode ||
0307         old_state->tv.brightness != new_state->tv.brightness ||
0308         old_state->tv.contrast != new_state->tv.contrast ||
0309         old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
0310         old_state->tv.overscan != new_state->tv.overscan ||
0311         old_state->tv.saturation != new_state->tv.saturation ||
0312         old_state->tv.hue != new_state->tv.hue)
0313         new_crtc_state->connectors_changed = true;
0314 
0315     return 0;
0316 }
0317 
0318 static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
0319     .detect_ctx = gud_connector_detect,
0320     .get_modes = gud_connector_get_modes,
0321     .atomic_check = gud_connector_atomic_check,
0322 };
0323 
0324 static int gud_connector_late_register(struct drm_connector *connector)
0325 {
0326     struct gud_connector *gconn = to_gud_connector(connector);
0327 
0328     if (gconn->initial_brightness < 0)
0329         return 0;
0330 
0331     return gud_connector_backlight_register(gconn);
0332 }
0333 
0334 static void gud_connector_early_unregister(struct drm_connector *connector)
0335 {
0336     struct gud_connector *gconn = to_gud_connector(connector);
0337 
0338     backlight_device_unregister(gconn->backlight);
0339     cancel_work_sync(&gconn->backlight_work);
0340 }
0341 
0342 static void gud_connector_destroy(struct drm_connector *connector)
0343 {
0344     struct gud_connector *gconn = to_gud_connector(connector);
0345 
0346     drm_connector_cleanup(connector);
0347     kfree(gconn->properties);
0348     kfree(gconn);
0349 }
0350 
0351 static void gud_connector_reset(struct drm_connector *connector)
0352 {
0353     struct gud_connector *gconn = to_gud_connector(connector);
0354 
0355     drm_atomic_helper_connector_reset(connector);
0356     connector->state->tv = gconn->initial_tv_state;
0357     /* Set margins from command line */
0358     drm_atomic_helper_connector_tv_reset(connector);
0359     if (gconn->initial_brightness >= 0)
0360         connector->state->tv.brightness = gconn->initial_brightness;
0361 }
0362 
0363 static const struct drm_connector_funcs gud_connector_funcs = {
0364     .fill_modes = drm_helper_probe_single_connector_modes,
0365     .late_register = gud_connector_late_register,
0366     .early_unregister = gud_connector_early_unregister,
0367     .destroy = gud_connector_destroy,
0368     .reset = gud_connector_reset,
0369     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0370     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0371 };
0372 
0373 /*
0374  * The tv.mode property is shared among the connectors and its enum names are
0375  * driver specific. This means that if more than one connector uses tv.mode,
0376  * the enum names has to be the same.
0377  */
0378 static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
0379 {
0380     size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
0381     const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
0382     unsigned int i, num_modes;
0383     char *buf;
0384     int ret;
0385 
0386     buf = kmalloc(buf_len, GFP_KERNEL);
0387     if (!buf)
0388         return -ENOMEM;
0389 
0390     ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
0391               connector->index, buf, buf_len);
0392     if (ret < 0)
0393         goto free;
0394     if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
0395         ret = -EIO;
0396         goto free;
0397     }
0398 
0399     num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
0400     for (i = 0; i < num_modes; i++)
0401         modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
0402 
0403     ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
0404 free:
0405     kfree(buf);
0406     if (ret < 0)
0407         gud_conn_err(connector, "Failed to add TV modes", ret);
0408 
0409     return ret;
0410 }
0411 
0412 static struct drm_property *
0413 gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
0414 {
0415     struct drm_mode_config *config = &connector->dev->mode_config;
0416 
0417     switch (prop) {
0418     case GUD_PROPERTY_TV_LEFT_MARGIN:
0419         return config->tv_left_margin_property;
0420     case GUD_PROPERTY_TV_RIGHT_MARGIN:
0421         return config->tv_right_margin_property;
0422     case GUD_PROPERTY_TV_TOP_MARGIN:
0423         return config->tv_top_margin_property;
0424     case GUD_PROPERTY_TV_BOTTOM_MARGIN:
0425         return config->tv_bottom_margin_property;
0426     case GUD_PROPERTY_TV_MODE:
0427         return config->tv_mode_property;
0428     case GUD_PROPERTY_TV_BRIGHTNESS:
0429         return config->tv_brightness_property;
0430     case GUD_PROPERTY_TV_CONTRAST:
0431         return config->tv_contrast_property;
0432     case GUD_PROPERTY_TV_FLICKER_REDUCTION:
0433         return config->tv_flicker_reduction_property;
0434     case GUD_PROPERTY_TV_OVERSCAN:
0435         return config->tv_overscan_property;
0436     case GUD_PROPERTY_TV_SATURATION:
0437         return config->tv_saturation_property;
0438     case GUD_PROPERTY_TV_HUE:
0439         return config->tv_hue_property;
0440     default:
0441         return ERR_PTR(-EINVAL);
0442     }
0443 }
0444 
0445 static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
0446 {
0447     switch (prop) {
0448     case GUD_PROPERTY_TV_LEFT_MARGIN:
0449         return &state->margins.left;
0450     case GUD_PROPERTY_TV_RIGHT_MARGIN:
0451         return &state->margins.right;
0452     case GUD_PROPERTY_TV_TOP_MARGIN:
0453         return &state->margins.top;
0454     case GUD_PROPERTY_TV_BOTTOM_MARGIN:
0455         return &state->margins.bottom;
0456     case GUD_PROPERTY_TV_MODE:
0457         return &state->mode;
0458     case GUD_PROPERTY_TV_BRIGHTNESS:
0459         return &state->brightness;
0460     case GUD_PROPERTY_TV_CONTRAST:
0461         return &state->contrast;
0462     case GUD_PROPERTY_TV_FLICKER_REDUCTION:
0463         return &state->flicker_reduction;
0464     case GUD_PROPERTY_TV_OVERSCAN:
0465         return &state->overscan;
0466     case GUD_PROPERTY_TV_SATURATION:
0467         return &state->saturation;
0468     case GUD_PROPERTY_TV_HUE:
0469         return &state->hue;
0470     default:
0471         return ERR_PTR(-EINVAL);
0472     }
0473 }
0474 
0475 static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
0476 {
0477     struct drm_connector *connector = &gconn->connector;
0478     struct drm_device *drm = &gdrm->drm;
0479     struct gud_property_req *properties;
0480     unsigned int i, num_properties;
0481     int ret;
0482 
0483     properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
0484     if (!properties)
0485         return -ENOMEM;
0486 
0487     ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
0488               properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
0489     if (ret <= 0)
0490         goto out;
0491     if (ret % sizeof(*properties)) {
0492         ret = -EIO;
0493         goto out;
0494     }
0495 
0496     num_properties = ret / sizeof(*properties);
0497     ret = 0;
0498 
0499     gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
0500     if (!gconn->properties) {
0501         ret = -ENOMEM;
0502         goto out;
0503     }
0504 
0505     for (i = 0; i < num_properties; i++) {
0506         u16 prop = le16_to_cpu(properties[i].prop);
0507         u64 val = le64_to_cpu(properties[i].val);
0508         struct drm_property *property;
0509         unsigned int *state_val;
0510 
0511         drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
0512 
0513         switch (prop) {
0514         case GUD_PROPERTY_TV_LEFT_MARGIN:
0515             fallthrough;
0516         case GUD_PROPERTY_TV_RIGHT_MARGIN:
0517             fallthrough;
0518         case GUD_PROPERTY_TV_TOP_MARGIN:
0519             fallthrough;
0520         case GUD_PROPERTY_TV_BOTTOM_MARGIN:
0521             ret = drm_mode_create_tv_margin_properties(drm);
0522             if (ret)
0523                 goto out;
0524             break;
0525         case GUD_PROPERTY_TV_MODE:
0526             ret = gud_connector_add_tv_mode(gdrm, connector);
0527             if (ret)
0528                 goto out;
0529             break;
0530         case GUD_PROPERTY_TV_BRIGHTNESS:
0531             fallthrough;
0532         case GUD_PROPERTY_TV_CONTRAST:
0533             fallthrough;
0534         case GUD_PROPERTY_TV_FLICKER_REDUCTION:
0535             fallthrough;
0536         case GUD_PROPERTY_TV_OVERSCAN:
0537             fallthrough;
0538         case GUD_PROPERTY_TV_SATURATION:
0539             fallthrough;
0540         case GUD_PROPERTY_TV_HUE:
0541             /* This is a no-op if already added. */
0542             ret = drm_mode_create_tv_properties(drm, 0, NULL);
0543             if (ret)
0544                 goto out;
0545             break;
0546         case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
0547             if (val > 100) {
0548                 ret = -EINVAL;
0549                 goto out;
0550             }
0551             gconn->initial_brightness = val;
0552             break;
0553         default:
0554             /* New ones might show up in future devices, skip those we don't know. */
0555             drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
0556             continue;
0557         }
0558 
0559         gconn->properties[gconn->num_properties++] = prop;
0560 
0561         if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
0562             continue; /* not a DRM property */
0563 
0564         property = gud_connector_property_lookup(connector, prop);
0565         if (WARN_ON(IS_ERR(property)))
0566             continue;
0567 
0568         state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
0569         if (WARN_ON(IS_ERR(state_val)))
0570             continue;
0571 
0572         *state_val = val;
0573         drm_object_attach_property(&connector->base, property, 0);
0574     }
0575 out:
0576     kfree(properties);
0577 
0578     return ret;
0579 }
0580 
0581 int gud_connector_fill_properties(struct drm_connector_state *connector_state,
0582                   struct gud_property_req *properties)
0583 {
0584     struct gud_connector *gconn = to_gud_connector(connector_state->connector);
0585     unsigned int i;
0586 
0587     for (i = 0; i < gconn->num_properties; i++) {
0588         u16 prop = gconn->properties[i];
0589         u64 val;
0590 
0591         if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
0592             val = connector_state->tv.brightness;
0593         } else {
0594             unsigned int *state_val;
0595 
0596             state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
0597             if (WARN_ON_ONCE(IS_ERR(state_val)))
0598                 return PTR_ERR(state_val);
0599 
0600             val = *state_val;
0601         }
0602 
0603         properties[i].prop = cpu_to_le16(prop);
0604         properties[i].val = cpu_to_le64(val);
0605     }
0606 
0607     return gconn->num_properties;
0608 }
0609 
0610 static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
0611                 struct gud_connector_descriptor_req *desc)
0612 {
0613     struct drm_device *drm = &gdrm->drm;
0614     struct gud_connector *gconn;
0615     struct drm_connector *connector;
0616     struct drm_encoder *encoder;
0617     int ret, connector_type;
0618     u32 flags;
0619 
0620     gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
0621     if (!gconn)
0622         return -ENOMEM;
0623 
0624     INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
0625     gconn->initial_brightness = -ENODEV;
0626     flags = le32_to_cpu(desc->flags);
0627     connector = &gconn->connector;
0628 
0629     drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
0630 
0631     switch (desc->connector_type) {
0632     case GUD_CONNECTOR_TYPE_PANEL:
0633         connector_type = DRM_MODE_CONNECTOR_USB;
0634         break;
0635     case GUD_CONNECTOR_TYPE_VGA:
0636         connector_type = DRM_MODE_CONNECTOR_VGA;
0637         break;
0638     case GUD_CONNECTOR_TYPE_DVI:
0639         connector_type = DRM_MODE_CONNECTOR_DVID;
0640         break;
0641     case GUD_CONNECTOR_TYPE_COMPOSITE:
0642         connector_type = DRM_MODE_CONNECTOR_Composite;
0643         break;
0644     case GUD_CONNECTOR_TYPE_SVIDEO:
0645         connector_type = DRM_MODE_CONNECTOR_SVIDEO;
0646         break;
0647     case GUD_CONNECTOR_TYPE_COMPONENT:
0648         connector_type = DRM_MODE_CONNECTOR_Component;
0649         break;
0650     case GUD_CONNECTOR_TYPE_DISPLAYPORT:
0651         connector_type = DRM_MODE_CONNECTOR_DisplayPort;
0652         break;
0653     case GUD_CONNECTOR_TYPE_HDMI:
0654         connector_type = DRM_MODE_CONNECTOR_HDMIA;
0655         break;
0656     default: /* future types */
0657         connector_type = DRM_MODE_CONNECTOR_USB;
0658         break;
0659     }
0660 
0661     drm_connector_helper_add(connector, &gud_connector_helper_funcs);
0662     ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
0663     if (ret) {
0664         kfree(connector);
0665         return ret;
0666     }
0667 
0668     if (WARN_ON(connector->index != index))
0669         return -EINVAL;
0670 
0671     if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
0672         connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
0673     if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
0674         connector->interlace_allowed = true;
0675     if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
0676         connector->doublescan_allowed = true;
0677 
0678     ret = gud_connector_add_properties(gdrm, gconn);
0679     if (ret) {
0680         gud_conn_err(connector, "Failed to add properties", ret);
0681         return ret;
0682     }
0683 
0684     /* The first connector is attached to the existing simple pipe encoder */
0685     if (!connector->index) {
0686         encoder = &gdrm->pipe.encoder;
0687     } else {
0688         encoder = &gconn->encoder;
0689 
0690         ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
0691         if (ret)
0692             return ret;
0693 
0694         encoder->possible_crtcs = 1;
0695     }
0696 
0697     return drm_connector_attach_encoder(connector, encoder);
0698 }
0699 
0700 int gud_get_connectors(struct gud_device *gdrm)
0701 {
0702     struct gud_connector_descriptor_req *descs;
0703     unsigned int i, num_connectors;
0704     int ret;
0705 
0706     descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
0707     if (!descs)
0708         return -ENOMEM;
0709 
0710     ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
0711               descs, GUD_CONNECTORS_MAX_NUM * sizeof(*descs));
0712     if (ret < 0)
0713         goto free;
0714     if (!ret || ret % sizeof(*descs)) {
0715         ret = -EIO;
0716         goto free;
0717     }
0718 
0719     num_connectors = ret / sizeof(*descs);
0720 
0721     for (i = 0; i < num_connectors; i++) {
0722         ret = gud_connector_create(gdrm, i, &descs[i]);
0723         if (ret)
0724             goto free;
0725     }
0726 free:
0727     kfree(descs);
0728 
0729     return ret;
0730 }