Signed-off-by: Louis Chauvet <[email protected]>
---
 drivers/gpu/drm/vkms/vkms_config.c   |  13 ++++
 drivers/gpu/drm/vkms/vkms_config.h   |   3 +
 drivers/gpu/drm/vkms/vkms_configfs.c | 138 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_configfs.h |  23 ++++++
 4 files changed, 177 insertions(+)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c 
b/drivers/gpu/drm/vkms/vkms_config.c
index 
9a461a0481c2a20d6d48f1aa9649843ad1b7d13d..da99785ec89f0c6a7fe1a71fd2e6f5944c844aa9
 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -516,6 +516,19 @@ vkms_config_connector_attach_encoder(struct 
vkms_config_connector *vkms_config_c
        return ret;
 }
 
+void vkms_config_connector_detach_encoder(struct vkms_config_connector 
*vkms_config_connector,
+                                         struct vkms_config_encoder 
*vkms_config_encoder)
+{
+       struct vkms_config_encoder *encoder_entry;
+       unsigned long encoder_idx;
+
+       xa_for_each(&vkms_config_connector->possible_encoders, encoder_idx, 
encoder_entry) {
+               if (encoder_entry == vkms_config_encoder)
+                       break;
+       }
+       xa_erase(&vkms_config_connector->possible_encoders, encoder_idx);
+}
+
 bool vkms_config_is_valid(struct vkms_config *config)
 {
        struct vkms_config_plane *config_plane;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h 
b/drivers/gpu/drm/vkms/vkms_config.h
index 
529d9c99f3c406d49dc7f3689a84c3dd775399a9..b1d80185216798cc9fc06e7d1cd0c423b7275185
 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -197,6 +197,9 @@ int __must_check vkms_config_encoder_attach_crtc(struct 
vkms_config_encoder *vkm
 int __must_check
 vkms_config_connector_attach_encoder(struct vkms_config_connector 
*vkms_config_connector,
                                     struct vkms_config_encoder 
*vkms_config_encoder);
+void vkms_config_connector_detach_encoder(struct vkms_config_connector 
*vkms_config_connector,
+                                         struct vkms_config_encoder 
*vkms_config_encoder);
+
 /**
  * vkms_config_delete_plane() - Remove a plane configuration and frees its 
memory
  *
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c 
b/drivers/gpu/drm/vkms/vkms_configfs.c
index 
a410c9be4f2bbf7b2651245747eb357fcf32d1f2..94c288514172b88d06c2b74e36569c6d55383782
 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -746,6 +746,7 @@ static struct config_group *encoder_make_group(struct 
config_group *config_group
        }
 
        strscpy(vkms_configfs_encoder->vkms_config_encoder->name, name, 
strlen(name) + 1);
+
        config_group_init_type_name(&vkms_configfs_encoder->group, name,
                                    &encoder_item_type);
 
@@ -769,6 +770,139 @@ static const struct config_item_type encoders_item_type = 
{
        .ct_owner       = THIS_MODULE,
 };
 
+static int connector_possible_encoders_allow_link(struct config_item *src,
+                                                 struct config_item *target)
+{
+       struct vkms_config_encoder *vkms_config_encoder;
+       struct vkms_configfs_device *vkms_configfs =
+               connector_possible_encoder_src_item_to_vkms_configfs_device
+               (src);
+
+       mutex_lock(&vkms_configfs->lock);
+
+       if (target->ci_type != &encoder_item_type) {
+               DRM_ERROR("Unable to link non-CRTCs.\n");
+               mutex_unlock(&vkms_configfs->lock);
+               return -EINVAL;
+       }
+
+       vkms_config_encoder = encoder_item_to_vkms_configfs_encoder(target)
+                                     ->vkms_config_encoder;
+       struct vkms_config_connector *vkms_config_connector =
+               connector_possible_encoder_src_item_to_vkms_configfs_connector
+               (src)
+                       ->vkms_config_connector;
+
+       if (vkms_config_connector_attach_encoder(vkms_config_connector,
+                                                vkms_config_encoder))
+               return -EINVAL;
+
+       mutex_unlock(&vkms_configfs->lock);
+
+       return 0;
+}
+
+static void connector_possible_encoders_drop_link(struct config_item *src,
+                                                 struct config_item *target)
+{
+       struct vkms_config_encoder *vkms_config_encoder;
+       struct vkms_configfs_device *vkms_configfs =
+               
connector_possible_encoder_src_item_to_vkms_configfs_device(src);
+
+       mutex_lock(&vkms_configfs->lock);
+
+       vkms_config_encoder = 
encoder_item_to_vkms_configfs_encoder(target)->vkms_config_encoder;
+       struct vkms_config_connector *vkms_config_connector =
+               
connector_possible_encoder_src_item_to_vkms_configfs_connector(src)
+                       ->vkms_config_connector;
+
+       vkms_config_connector_detach_encoder(vkms_config_connector, 
vkms_config_encoder);
+
+       mutex_unlock(&vkms_configfs->lock);
+}
+
+static struct configfs_item_operations 
connector_possible_encoders_item_operations = {
+       .allow_link = &connector_possible_encoders_allow_link,
+       .drop_link = &connector_possible_encoders_drop_link,
+};
+
+static struct config_item_type connector_possible_encoders_item_type = {
+       .ct_item_ops = &connector_possible_encoders_item_operations,
+       .ct_owner = THIS_MODULE,
+};
+
+static void connector_release(struct config_item *item)
+{
+       struct vkms_configfs_connector *vkms_configfs_connector =
+               connector_item_to_vkms_configfs_connector(item);
+
+       mutex_lock(&vkms_configfs_connector->vkms_configfs_device->lock);
+       
vkms_config_delete_connector(vkms_configfs_connector->vkms_config_connector);
+       mutex_unlock(&vkms_configfs_connector->vkms_configfs_device->lock);
+
+       kfree(vkms_configfs_connector);
+}
+
+static struct configfs_item_operations connector_item_operations = {
+       .release = connector_release,
+};
+
+static const struct config_item_type connector_item_type = {
+       .ct_item_ops = &connector_item_operations,
+       .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *connector_make_group(struct config_group 
*config_group,
+                                                const char *name)
+{
+       struct vkms_configfs_device *vkms_configfs =
+               connector_item_to_vkms_configfs_device(&config_group->cg_item);
+       struct vkms_configfs_connector *vkms_configfs_connector;
+
+       vkms_configfs_connector = kzalloc(sizeof(*vkms_configfs_connector), 
GFP_KERNEL);
+
+       if (!vkms_configfs_connector)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_lock(&vkms_configfs->lock);
+
+       if (vkms_configfs->enabled) {
+               kfree(vkms_configfs_connector);
+               mutex_unlock(&vkms_configfs->lock);
+               return ERR_PTR(-EINVAL);
+       }
+
+       vkms_configfs_connector->vkms_config_connector =
+               vkms_config_create_connector(vkms_configfs->vkms_config);
+
+       if (!vkms_configfs_connector->vkms_config_connector) {
+               kfree(vkms_configfs_connector);
+               mutex_unlock(&vkms_configfs->lock);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       config_group_init_type_name(&vkms_configfs_connector->group, name, 
&connector_item_type);
+
+       
config_group_init_type_name(&vkms_configfs_connector->possible_encoder_group,
+                                   "possible_encoders", 
&connector_possible_encoders_item_type);
+       
configfs_add_default_group(&vkms_configfs_connector->possible_encoder_group,
+                                  &vkms_configfs_connector->group);
+       vkms_configfs_connector->vkms_configfs_device = vkms_configfs;
+
+       mutex_unlock(&vkms_configfs->lock);
+
+       return &vkms_configfs_connector->group;
+}
+
+static struct configfs_group_operations connector_group_operations = {
+       .make_group = &connector_make_group,
+};
+
+static const struct config_item_type connectors_item_type = {
+       .ct_group_ops = &connector_group_operations,
+       .ct_owner = THIS_MODULE,
+};
+
 /**
  * configfs_lock_dependencies() - In order to forbid the userspace to delete 
items when the
  * device is enabled, mark all configfs items as dependent
@@ -915,6 +1049,10 @@ static struct config_group *root_make_group(struct 
config_group *group,
        config_group_init_type_name(&configfs->encoder_group, "encoders", 
&encoders_item_type);
        configfs_add_default_group(&configfs->encoder_group, &configfs->group);
 
+       config_group_init_type_name(&configfs->connector_group, "connectors",
+                                   &connectors_item_type);
+       configfs_add_default_group(&configfs->connector_group, 
&configfs->group);
+
        return &configfs->group;
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h 
b/drivers/gpu/drm/vkms/vkms_configfs.h
index 
df743e0107f40cd10433bdb638108d266f9c83a6..12c0fdefb813387515d144519479c242b7ef6728
 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.h
+++ b/drivers/gpu/drm/vkms/vkms_configfs.h
@@ -22,6 +22,7 @@ struct vkms_configfs_device {
        struct config_group plane_group;
        struct config_group crtc_group;
        struct config_group encoder_group;
+       struct config_group connector_group;
 
        struct mutex lock;
        bool enabled;
@@ -53,6 +54,14 @@ struct vkms_configfs_encoder {
        struct vkms_config_encoder *vkms_config_encoder;
 };
 
+struct vkms_configfs_connector {
+       struct config_group group;
+
+       struct config_group possible_encoder_group;
+       struct vkms_configfs_device *vkms_configfs_device;
+       struct vkms_config_connector *vkms_config_connector;
+};
+
 #define config_item_to_vkms_configfs_device(item) \
        container_of(to_config_group((item)), struct vkms_configfs_device, 
group)
 
@@ -68,6 +77,9 @@ struct vkms_configfs_encoder {
 #define encoder_item_to_vkms_configfs_encoder(item) \
        container_of(to_config_group((item)), struct vkms_configfs_encoder, 
group)
 
+#define connector_item_to_vkms_configfs_connector(item) \
+       container_of(to_config_group((item)), struct vkms_configfs_connector, 
group)
+
 #define plane_item_to_vkms_configfs_device(item) \
        planes_item_to_vkms_configfs_device((item)->ci_parent)
 
@@ -89,14 +101,25 @@ struct vkms_configfs_encoder {
 #define encoder_item_to_vkms_configfs_device(item) \
        config_item_to_vkms_configfs_device((item)->ci_parent)
 
+#define connector_item_to_vkms_configfs_device(item) \
+       config_item_to_vkms_configfs_device((item)->ci_parent)
+
 #define encoder_child_item_to_vkms_configfs_device(item) \
        encoder_item_to_vkms_configfs_device((item)->ci_parent)
 
 #define encoder_possible_crtc_src_item_to_vkms_configfs_device(item) \
        encoder_child_item_to_vkms_configfs_device((item)->ci_parent)
 
+#define connector_child_item_to_vkms_configfs_device(item) \
+       connector_item_to_vkms_configfs_device((item)->ci_parent)
+
+#define connector_possible_encoder_src_item_to_vkms_configfs_device(item) \
+       connector_child_item_to_vkms_configfs_device((item)->ci_parent)
+
 #define encoder_possible_crtc_src_item_to_vkms_configfs_encoder(item) \
        encoder_item_to_vkms_configfs_encoder((item)->ci_parent)
+#define connector_possible_encoder_src_item_to_vkms_configfs_connector(item) \
+       connector_item_to_vkms_configfs_connector((item)->ci_parent)
 
 /* ConfigFS Support */
 int vkms_init_configfs(void);

-- 
2.47.0

Reply via email to