113fc9b97SLouis Chauvet // SPDX-License-Identifier: GPL-2.0+ 213fc9b97SLouis Chauvet #include <linux/cleanup.h> 313fc9b97SLouis Chauvet #include <linux/configfs.h> 413fc9b97SLouis Chauvet #include <linux/mutex.h> 513fc9b97SLouis Chauvet #include <linux/slab.h> 613fc9b97SLouis Chauvet 713fc9b97SLouis Chauvet #include "vkms_drv.h" 813fc9b97SLouis Chauvet #include "vkms_config.h" 913fc9b97SLouis Chauvet #include "vkms_configfs.h" 10f97180f0SJosé Expósito #include "vkms_connector.h" 1113fc9b97SLouis Chauvet 1213fc9b97SLouis Chauvet /* To avoid registering configfs more than once or unregistering on error */ 1313fc9b97SLouis Chauvet static bool is_configfs_registered; 1413fc9b97SLouis Chauvet 1513fc9b97SLouis Chauvet /** 1613fc9b97SLouis Chauvet * struct vkms_configfs_device - Configfs representation of a VKMS device 1713fc9b97SLouis Chauvet * 1813fc9b97SLouis Chauvet * @group: Top level configuration group that represents a VKMS device. 1913fc9b97SLouis Chauvet * Initialized when a new directory is created under "/config/vkms/" 202f1734baSLouis Chauvet * @planes_group: Default subgroup of @group at "/config/vkms/planes" 213e4d5b30SLouis Chauvet * @crtcs_group: Default subgroup of @group at "/config/vkms/crtcs" 2267d8cf92SLouis Chauvet * @encoders_group: Default subgroup of @group at "/config/vkms/encoders" 23272acbcaSLouis Chauvet * @connectors_group: Default subgroup of @group at "/config/vkms/connectors" 2413fc9b97SLouis Chauvet * @lock: Lock used to project concurrent access to the configuration attributes 2513fc9b97SLouis Chauvet * @config: Protected by @lock. Configuration of the VKMS device 2613fc9b97SLouis Chauvet * @enabled: Protected by @lock. The device is created or destroyed when this 2713fc9b97SLouis Chauvet * option changes 2813fc9b97SLouis Chauvet */ 2913fc9b97SLouis Chauvet struct vkms_configfs_device { 3013fc9b97SLouis Chauvet struct config_group group; 312f1734baSLouis Chauvet struct config_group planes_group; 323e4d5b30SLouis Chauvet struct config_group crtcs_group; 3367d8cf92SLouis Chauvet struct config_group encoders_group; 34272acbcaSLouis Chauvet struct config_group connectors_group; 3513fc9b97SLouis Chauvet 3613fc9b97SLouis Chauvet struct mutex lock; 3713fc9b97SLouis Chauvet struct vkms_config *config; 3813fc9b97SLouis Chauvet bool enabled; 3913fc9b97SLouis Chauvet }; 4013fc9b97SLouis Chauvet 412f1734baSLouis Chauvet /** 422f1734baSLouis Chauvet * struct vkms_configfs_plane - Configfs representation of a plane 432f1734baSLouis Chauvet * 442f1734baSLouis Chauvet * @group: Top level configuration group that represents a plane. 452f1734baSLouis Chauvet * Initialized when a new directory is created under "/config/vkms/planes" 4695fa7378SLouis Chauvet * @possible_crtcs_group: Default subgroup of @group at "plane/possible_crtcs" 472f1734baSLouis Chauvet * @dev: The vkms_configfs_device this plane belongs to 482f1734baSLouis Chauvet * @config: Configuration of the VKMS plane 492f1734baSLouis Chauvet */ 502f1734baSLouis Chauvet struct vkms_configfs_plane { 512f1734baSLouis Chauvet struct config_group group; 5295fa7378SLouis Chauvet struct config_group possible_crtcs_group; 532f1734baSLouis Chauvet struct vkms_configfs_device *dev; 542f1734baSLouis Chauvet struct vkms_config_plane *config; 552f1734baSLouis Chauvet }; 562f1734baSLouis Chauvet 573e4d5b30SLouis Chauvet /** 583e4d5b30SLouis Chauvet * struct vkms_configfs_crtc - Configfs representation of a CRTC 593e4d5b30SLouis Chauvet * 603e4d5b30SLouis Chauvet * @group: Top level configuration group that represents a CRTC. 613e4d5b30SLouis Chauvet * Initialized when a new directory is created under "/config/vkms/crtcs" 623e4d5b30SLouis Chauvet * @dev: The vkms_configfs_device this CRTC belongs to 633e4d5b30SLouis Chauvet * @config: Configuration of the VKMS CRTC 643e4d5b30SLouis Chauvet */ 653e4d5b30SLouis Chauvet struct vkms_configfs_crtc { 663e4d5b30SLouis Chauvet struct config_group group; 673e4d5b30SLouis Chauvet struct vkms_configfs_device *dev; 683e4d5b30SLouis Chauvet struct vkms_config_crtc *config; 693e4d5b30SLouis Chauvet }; 703e4d5b30SLouis Chauvet 7167d8cf92SLouis Chauvet /** 7267d8cf92SLouis Chauvet * struct vkms_configfs_encoder - Configfs representation of a encoder 7367d8cf92SLouis Chauvet * 7467d8cf92SLouis Chauvet * @group: Top level configuration group that represents a encoder. 7567d8cf92SLouis Chauvet * Initialized when a new directory is created under "/config/vkms/encoders" 76fad1138bSLouis Chauvet * @possible_crtcs_group: Default subgroup of @group at "encoder/possible_crtcs" 7767d8cf92SLouis Chauvet * @dev: The vkms_configfs_device this encoder belongs to 7867d8cf92SLouis Chauvet * @config: Configuration of the VKMS encoder 7967d8cf92SLouis Chauvet */ 8067d8cf92SLouis Chauvet struct vkms_configfs_encoder { 8167d8cf92SLouis Chauvet struct config_group group; 82fad1138bSLouis Chauvet struct config_group possible_crtcs_group; 8367d8cf92SLouis Chauvet struct vkms_configfs_device *dev; 8467d8cf92SLouis Chauvet struct vkms_config_encoder *config; 8567d8cf92SLouis Chauvet }; 8667d8cf92SLouis Chauvet 87272acbcaSLouis Chauvet /** 88272acbcaSLouis Chauvet * struct vkms_configfs_connector - Configfs representation of a connector 89272acbcaSLouis Chauvet * 90272acbcaSLouis Chauvet * @group: Top level configuration group that represents a connector. 91272acbcaSLouis Chauvet * Initialized when a new directory is created under "/config/vkms/connectors" 9264229b84SLouis Chauvet * @possible_encoders_group: Default subgroup of @group at 9364229b84SLouis Chauvet * "connector/possible_encoders" 94272acbcaSLouis Chauvet * @dev: The vkms_configfs_device this connector belongs to 95272acbcaSLouis Chauvet * @config: Configuration of the VKMS connector 96272acbcaSLouis Chauvet */ 97272acbcaSLouis Chauvet struct vkms_configfs_connector { 98272acbcaSLouis Chauvet struct config_group group; 9964229b84SLouis Chauvet struct config_group possible_encoders_group; 100272acbcaSLouis Chauvet struct vkms_configfs_device *dev; 101272acbcaSLouis Chauvet struct vkms_config_connector *config; 102272acbcaSLouis Chauvet }; 103272acbcaSLouis Chauvet 10413fc9b97SLouis Chauvet #define device_item_to_vkms_configfs_device(item) \ 10513fc9b97SLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_device, \ 10613fc9b97SLouis Chauvet group) 10713fc9b97SLouis Chauvet 1082f1734baSLouis Chauvet #define child_group_to_vkms_configfs_device(group) \ 1092f1734baSLouis Chauvet device_item_to_vkms_configfs_device((&(group)->cg_item)->ci_parent) 1102f1734baSLouis Chauvet 1112f1734baSLouis Chauvet #define plane_item_to_vkms_configfs_plane(item) \ 1122f1734baSLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_plane, group) 1132f1734baSLouis Chauvet 11495fa7378SLouis Chauvet #define plane_possible_crtcs_item_to_vkms_configfs_plane(item) \ 11595fa7378SLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_plane, \ 11695fa7378SLouis Chauvet possible_crtcs_group) 11795fa7378SLouis Chauvet 1183e4d5b30SLouis Chauvet #define crtc_item_to_vkms_configfs_crtc(item) \ 1193e4d5b30SLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_crtc, group) 1203e4d5b30SLouis Chauvet 12167d8cf92SLouis Chauvet #define encoder_item_to_vkms_configfs_encoder(item) \ 12267d8cf92SLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_encoder, \ 12367d8cf92SLouis Chauvet group) 12467d8cf92SLouis Chauvet 125fad1138bSLouis Chauvet #define encoder_possible_crtcs_item_to_vkms_configfs_encoder(item) \ 126fad1138bSLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_encoder, \ 127fad1138bSLouis Chauvet possible_crtcs_group) 128fad1138bSLouis Chauvet 129272acbcaSLouis Chauvet #define connector_item_to_vkms_configfs_connector(item) \ 130272acbcaSLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_connector, \ 131272acbcaSLouis Chauvet group) 132272acbcaSLouis Chauvet 13364229b84SLouis Chauvet #define connector_possible_encoders_item_to_vkms_configfs_connector(item) \ 13464229b84SLouis Chauvet container_of(to_config_group((item)), struct vkms_configfs_connector, \ 13564229b84SLouis Chauvet possible_encoders_group) 13664229b84SLouis Chauvet 137ee5c2c7dSLouis Chauvet static ssize_t crtc_writeback_show(struct config_item *item, char *page) 138ee5c2c7dSLouis Chauvet { 139ee5c2c7dSLouis Chauvet struct vkms_configfs_crtc *crtc; 140ee5c2c7dSLouis Chauvet bool writeback; 141ee5c2c7dSLouis Chauvet 142ee5c2c7dSLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(item); 143ee5c2c7dSLouis Chauvet 144ee5c2c7dSLouis Chauvet scoped_guard(mutex, &crtc->dev->lock) 145ee5c2c7dSLouis Chauvet writeback = vkms_config_crtc_get_writeback(crtc->config); 146ee5c2c7dSLouis Chauvet 147ee5c2c7dSLouis Chauvet return sprintf(page, "%d\n", writeback); 148ee5c2c7dSLouis Chauvet } 149ee5c2c7dSLouis Chauvet 150ee5c2c7dSLouis Chauvet static ssize_t crtc_writeback_store(struct config_item *item, const char *page, 151ee5c2c7dSLouis Chauvet size_t count) 152ee5c2c7dSLouis Chauvet { 153ee5c2c7dSLouis Chauvet struct vkms_configfs_crtc *crtc; 154ee5c2c7dSLouis Chauvet bool writeback; 155ee5c2c7dSLouis Chauvet 156ee5c2c7dSLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(item); 157ee5c2c7dSLouis Chauvet 158ee5c2c7dSLouis Chauvet if (kstrtobool(page, &writeback)) 159ee5c2c7dSLouis Chauvet return -EINVAL; 160ee5c2c7dSLouis Chauvet 161ee5c2c7dSLouis Chauvet scoped_guard(mutex, &crtc->dev->lock) { 162ee5c2c7dSLouis Chauvet if (crtc->dev->enabled) 163ee5c2c7dSLouis Chauvet return -EBUSY; 164ee5c2c7dSLouis Chauvet 165ee5c2c7dSLouis Chauvet vkms_config_crtc_set_writeback(crtc->config, writeback); 166ee5c2c7dSLouis Chauvet } 167ee5c2c7dSLouis Chauvet 168ee5c2c7dSLouis Chauvet return (ssize_t)count; 169ee5c2c7dSLouis Chauvet } 170ee5c2c7dSLouis Chauvet 171ee5c2c7dSLouis Chauvet CONFIGFS_ATTR(crtc_, writeback); 172ee5c2c7dSLouis Chauvet 173ee5c2c7dSLouis Chauvet static struct configfs_attribute *crtc_item_attrs[] = { 174ee5c2c7dSLouis Chauvet &crtc_attr_writeback, 175ee5c2c7dSLouis Chauvet NULL, 176ee5c2c7dSLouis Chauvet }; 177ee5c2c7dSLouis Chauvet 1783e4d5b30SLouis Chauvet static void crtc_release(struct config_item *item) 1793e4d5b30SLouis Chauvet { 1803e4d5b30SLouis Chauvet struct vkms_configfs_crtc *crtc; 1813e4d5b30SLouis Chauvet struct mutex *lock; 1823e4d5b30SLouis Chauvet 1833e4d5b30SLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(item); 1843e4d5b30SLouis Chauvet lock = &crtc->dev->lock; 1853e4d5b30SLouis Chauvet 1863e4d5b30SLouis Chauvet scoped_guard(mutex, lock) { 1873e4d5b30SLouis Chauvet vkms_config_destroy_crtc(crtc->dev->config, crtc->config); 1883e4d5b30SLouis Chauvet kfree(crtc); 1893e4d5b30SLouis Chauvet } 1903e4d5b30SLouis Chauvet } 1913e4d5b30SLouis Chauvet 1923e4d5b30SLouis Chauvet static struct configfs_item_operations crtc_item_operations = { 1933e4d5b30SLouis Chauvet .release = &crtc_release, 1943e4d5b30SLouis Chauvet }; 1953e4d5b30SLouis Chauvet 1963e4d5b30SLouis Chauvet static const struct config_item_type crtc_item_type = { 197ee5c2c7dSLouis Chauvet .ct_attrs = crtc_item_attrs, 1983e4d5b30SLouis Chauvet .ct_item_ops = &crtc_item_operations, 1993e4d5b30SLouis Chauvet .ct_owner = THIS_MODULE, 2003e4d5b30SLouis Chauvet }; 2013e4d5b30SLouis Chauvet 2023e4d5b30SLouis Chauvet static struct config_group *make_crtc_group(struct config_group *group, 2033e4d5b30SLouis Chauvet const char *name) 2043e4d5b30SLouis Chauvet { 2053e4d5b30SLouis Chauvet struct vkms_configfs_device *dev; 2063e4d5b30SLouis Chauvet struct vkms_configfs_crtc *crtc; 207*f9e46accSDan Carpenter int ret; 2083e4d5b30SLouis Chauvet 2093e4d5b30SLouis Chauvet dev = child_group_to_vkms_configfs_device(group); 2103e4d5b30SLouis Chauvet 2113e4d5b30SLouis Chauvet scoped_guard(mutex, &dev->lock) { 2123e4d5b30SLouis Chauvet if (dev->enabled) 2133e4d5b30SLouis Chauvet return ERR_PTR(-EBUSY); 2143e4d5b30SLouis Chauvet 2153e4d5b30SLouis Chauvet crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); 2163e4d5b30SLouis Chauvet if (!crtc) 2173e4d5b30SLouis Chauvet return ERR_PTR(-ENOMEM); 2183e4d5b30SLouis Chauvet 2193e4d5b30SLouis Chauvet crtc->dev = dev; 2203e4d5b30SLouis Chauvet 2213e4d5b30SLouis Chauvet crtc->config = vkms_config_create_crtc(dev->config); 2223e4d5b30SLouis Chauvet if (IS_ERR(crtc->config)) { 223*f9e46accSDan Carpenter ret = PTR_ERR(crtc->config); 2243e4d5b30SLouis Chauvet kfree(crtc); 225*f9e46accSDan Carpenter return ERR_PTR(ret); 2263e4d5b30SLouis Chauvet } 2273e4d5b30SLouis Chauvet 2283e4d5b30SLouis Chauvet config_group_init_type_name(&crtc->group, name, &crtc_item_type); 2293e4d5b30SLouis Chauvet } 2303e4d5b30SLouis Chauvet 2313e4d5b30SLouis Chauvet return &crtc->group; 2323e4d5b30SLouis Chauvet } 2333e4d5b30SLouis Chauvet 2343e4d5b30SLouis Chauvet static struct configfs_group_operations crtcs_group_operations = { 2353e4d5b30SLouis Chauvet .make_group = &make_crtc_group, 2363e4d5b30SLouis Chauvet }; 2373e4d5b30SLouis Chauvet 2383e4d5b30SLouis Chauvet static const struct config_item_type crtc_group_type = { 2393e4d5b30SLouis Chauvet .ct_group_ops = &crtcs_group_operations, 2403e4d5b30SLouis Chauvet .ct_owner = THIS_MODULE, 2413e4d5b30SLouis Chauvet }; 2423e4d5b30SLouis Chauvet 24395fa7378SLouis Chauvet static int plane_possible_crtcs_allow_link(struct config_item *src, 24495fa7378SLouis Chauvet struct config_item *target) 24595fa7378SLouis Chauvet { 24695fa7378SLouis Chauvet struct vkms_configfs_plane *plane; 24795fa7378SLouis Chauvet struct vkms_configfs_crtc *crtc; 24895fa7378SLouis Chauvet int ret; 24995fa7378SLouis Chauvet 25095fa7378SLouis Chauvet if (target->ci_type != &crtc_item_type) 25195fa7378SLouis Chauvet return -EINVAL; 25295fa7378SLouis Chauvet 25395fa7378SLouis Chauvet plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src); 25495fa7378SLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(target); 25595fa7378SLouis Chauvet 25695fa7378SLouis Chauvet scoped_guard(mutex, &plane->dev->lock) { 25795fa7378SLouis Chauvet if (plane->dev->enabled) 25895fa7378SLouis Chauvet return -EBUSY; 25995fa7378SLouis Chauvet 26095fa7378SLouis Chauvet ret = vkms_config_plane_attach_crtc(plane->config, crtc->config); 26195fa7378SLouis Chauvet } 26295fa7378SLouis Chauvet 26395fa7378SLouis Chauvet return ret; 26495fa7378SLouis Chauvet } 26595fa7378SLouis Chauvet 26695fa7378SLouis Chauvet static void plane_possible_crtcs_drop_link(struct config_item *src, 26795fa7378SLouis Chauvet struct config_item *target) 26895fa7378SLouis Chauvet { 26995fa7378SLouis Chauvet struct vkms_configfs_plane *plane; 27095fa7378SLouis Chauvet struct vkms_configfs_crtc *crtc; 27195fa7378SLouis Chauvet 27295fa7378SLouis Chauvet plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src); 27395fa7378SLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(target); 27495fa7378SLouis Chauvet 27595fa7378SLouis Chauvet scoped_guard(mutex, &plane->dev->lock) 27695fa7378SLouis Chauvet vkms_config_plane_detach_crtc(plane->config, crtc->config); 27795fa7378SLouis Chauvet } 27895fa7378SLouis Chauvet 27995fa7378SLouis Chauvet static struct configfs_item_operations plane_possible_crtcs_item_operations = { 28095fa7378SLouis Chauvet .allow_link = plane_possible_crtcs_allow_link, 28195fa7378SLouis Chauvet .drop_link = plane_possible_crtcs_drop_link, 28295fa7378SLouis Chauvet }; 28395fa7378SLouis Chauvet 28495fa7378SLouis Chauvet static const struct config_item_type plane_possible_crtcs_group_type = { 28595fa7378SLouis Chauvet .ct_item_ops = &plane_possible_crtcs_item_operations, 28695fa7378SLouis Chauvet .ct_owner = THIS_MODULE, 28795fa7378SLouis Chauvet }; 28895fa7378SLouis Chauvet 289187bc306SLouis Chauvet static ssize_t plane_type_show(struct config_item *item, char *page) 290187bc306SLouis Chauvet { 291187bc306SLouis Chauvet struct vkms_configfs_plane *plane; 292187bc306SLouis Chauvet enum drm_plane_type type; 293187bc306SLouis Chauvet 294187bc306SLouis Chauvet plane = plane_item_to_vkms_configfs_plane(item); 295187bc306SLouis Chauvet 296187bc306SLouis Chauvet scoped_guard(mutex, &plane->dev->lock) 297187bc306SLouis Chauvet type = vkms_config_plane_get_type(plane->config); 298187bc306SLouis Chauvet 299187bc306SLouis Chauvet return sprintf(page, "%u", type); 300187bc306SLouis Chauvet } 301187bc306SLouis Chauvet 302187bc306SLouis Chauvet static ssize_t plane_type_store(struct config_item *item, const char *page, 303187bc306SLouis Chauvet size_t count) 304187bc306SLouis Chauvet { 305187bc306SLouis Chauvet struct vkms_configfs_plane *plane; 306187bc306SLouis Chauvet enum drm_plane_type type; 307187bc306SLouis Chauvet 308187bc306SLouis Chauvet plane = plane_item_to_vkms_configfs_plane(item); 309187bc306SLouis Chauvet 310187bc306SLouis Chauvet if (kstrtouint(page, 10, &type)) 311187bc306SLouis Chauvet return -EINVAL; 312187bc306SLouis Chauvet 313187bc306SLouis Chauvet if (type != DRM_PLANE_TYPE_OVERLAY && type != DRM_PLANE_TYPE_PRIMARY && 314187bc306SLouis Chauvet type != DRM_PLANE_TYPE_CURSOR) 315187bc306SLouis Chauvet return -EINVAL; 316187bc306SLouis Chauvet 317187bc306SLouis Chauvet scoped_guard(mutex, &plane->dev->lock) { 318187bc306SLouis Chauvet if (plane->dev->enabled) 319187bc306SLouis Chauvet return -EBUSY; 320187bc306SLouis Chauvet 321187bc306SLouis Chauvet vkms_config_plane_set_type(plane->config, type); 322187bc306SLouis Chauvet } 323187bc306SLouis Chauvet 324187bc306SLouis Chauvet return (ssize_t)count; 325187bc306SLouis Chauvet } 326187bc306SLouis Chauvet 327187bc306SLouis Chauvet CONFIGFS_ATTR(plane_, type); 328187bc306SLouis Chauvet 329187bc306SLouis Chauvet static struct configfs_attribute *plane_item_attrs[] = { 330187bc306SLouis Chauvet &plane_attr_type, 331187bc306SLouis Chauvet NULL, 332187bc306SLouis Chauvet }; 333187bc306SLouis Chauvet 3342f1734baSLouis Chauvet static void plane_release(struct config_item *item) 3352f1734baSLouis Chauvet { 3362f1734baSLouis Chauvet struct vkms_configfs_plane *plane; 3372f1734baSLouis Chauvet struct mutex *lock; 3382f1734baSLouis Chauvet 3392f1734baSLouis Chauvet plane = plane_item_to_vkms_configfs_plane(item); 3402f1734baSLouis Chauvet lock = &plane->dev->lock; 3412f1734baSLouis Chauvet 3422f1734baSLouis Chauvet scoped_guard(mutex, lock) { 3432f1734baSLouis Chauvet vkms_config_destroy_plane(plane->config); 3442f1734baSLouis Chauvet kfree(plane); 3452f1734baSLouis Chauvet } 3462f1734baSLouis Chauvet } 3472f1734baSLouis Chauvet 3482f1734baSLouis Chauvet static struct configfs_item_operations plane_item_operations = { 3492f1734baSLouis Chauvet .release = &plane_release, 3502f1734baSLouis Chauvet }; 3512f1734baSLouis Chauvet 3522f1734baSLouis Chauvet static const struct config_item_type plane_item_type = { 353187bc306SLouis Chauvet .ct_attrs = plane_item_attrs, 3542f1734baSLouis Chauvet .ct_item_ops = &plane_item_operations, 3552f1734baSLouis Chauvet .ct_owner = THIS_MODULE, 3562f1734baSLouis Chauvet }; 3572f1734baSLouis Chauvet 3582f1734baSLouis Chauvet static struct config_group *make_plane_group(struct config_group *group, 3592f1734baSLouis Chauvet const char *name) 3602f1734baSLouis Chauvet { 3612f1734baSLouis Chauvet struct vkms_configfs_device *dev; 3622f1734baSLouis Chauvet struct vkms_configfs_plane *plane; 363*f9e46accSDan Carpenter int ret; 3642f1734baSLouis Chauvet 3652f1734baSLouis Chauvet dev = child_group_to_vkms_configfs_device(group); 3662f1734baSLouis Chauvet 3672f1734baSLouis Chauvet scoped_guard(mutex, &dev->lock) { 3682f1734baSLouis Chauvet if (dev->enabled) 3692f1734baSLouis Chauvet return ERR_PTR(-EBUSY); 3702f1734baSLouis Chauvet 3712f1734baSLouis Chauvet plane = kzalloc(sizeof(*plane), GFP_KERNEL); 3722f1734baSLouis Chauvet if (!plane) 3732f1734baSLouis Chauvet return ERR_PTR(-ENOMEM); 3742f1734baSLouis Chauvet 3752f1734baSLouis Chauvet plane->dev = dev; 3762f1734baSLouis Chauvet 3772f1734baSLouis Chauvet plane->config = vkms_config_create_plane(dev->config); 3782f1734baSLouis Chauvet if (IS_ERR(plane->config)) { 379*f9e46accSDan Carpenter ret = PTR_ERR(plane->config); 3802f1734baSLouis Chauvet kfree(plane); 381*f9e46accSDan Carpenter return ERR_PTR(ret); 3822f1734baSLouis Chauvet } 3832f1734baSLouis Chauvet 3842f1734baSLouis Chauvet config_group_init_type_name(&plane->group, name, &plane_item_type); 38595fa7378SLouis Chauvet 38695fa7378SLouis Chauvet config_group_init_type_name(&plane->possible_crtcs_group, 38795fa7378SLouis Chauvet "possible_crtcs", 38895fa7378SLouis Chauvet &plane_possible_crtcs_group_type); 38995fa7378SLouis Chauvet configfs_add_default_group(&plane->possible_crtcs_group, 39095fa7378SLouis Chauvet &plane->group); 3912f1734baSLouis Chauvet } 3922f1734baSLouis Chauvet 3932f1734baSLouis Chauvet return &plane->group; 3942f1734baSLouis Chauvet } 3952f1734baSLouis Chauvet 3962f1734baSLouis Chauvet static struct configfs_group_operations planes_group_operations = { 3972f1734baSLouis Chauvet .make_group = &make_plane_group, 3982f1734baSLouis Chauvet }; 3992f1734baSLouis Chauvet 4002f1734baSLouis Chauvet static const struct config_item_type plane_group_type = { 4012f1734baSLouis Chauvet .ct_group_ops = &planes_group_operations, 4022f1734baSLouis Chauvet .ct_owner = THIS_MODULE, 4032f1734baSLouis Chauvet }; 4042f1734baSLouis Chauvet 405fad1138bSLouis Chauvet static int encoder_possible_crtcs_allow_link(struct config_item *src, 406fad1138bSLouis Chauvet struct config_item *target) 407fad1138bSLouis Chauvet { 408fad1138bSLouis Chauvet struct vkms_configfs_encoder *encoder; 409fad1138bSLouis Chauvet struct vkms_configfs_crtc *crtc; 410fad1138bSLouis Chauvet int ret; 411fad1138bSLouis Chauvet 412fad1138bSLouis Chauvet if (target->ci_type != &crtc_item_type) 413fad1138bSLouis Chauvet return -EINVAL; 414fad1138bSLouis Chauvet 415fad1138bSLouis Chauvet encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src); 416fad1138bSLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(target); 417fad1138bSLouis Chauvet 418fad1138bSLouis Chauvet scoped_guard(mutex, &encoder->dev->lock) { 419fad1138bSLouis Chauvet if (encoder->dev->enabled) 420fad1138bSLouis Chauvet return -EBUSY; 421fad1138bSLouis Chauvet 422fad1138bSLouis Chauvet ret = vkms_config_encoder_attach_crtc(encoder->config, crtc->config); 423fad1138bSLouis Chauvet } 424fad1138bSLouis Chauvet 425fad1138bSLouis Chauvet return ret; 426fad1138bSLouis Chauvet } 427fad1138bSLouis Chauvet 428fad1138bSLouis Chauvet static void encoder_possible_crtcs_drop_link(struct config_item *src, 429fad1138bSLouis Chauvet struct config_item *target) 430fad1138bSLouis Chauvet { 431fad1138bSLouis Chauvet struct vkms_configfs_encoder *encoder; 432fad1138bSLouis Chauvet struct vkms_configfs_crtc *crtc; 433fad1138bSLouis Chauvet 434fad1138bSLouis Chauvet encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src); 435fad1138bSLouis Chauvet crtc = crtc_item_to_vkms_configfs_crtc(target); 436fad1138bSLouis Chauvet 437fad1138bSLouis Chauvet scoped_guard(mutex, &encoder->dev->lock) 438fad1138bSLouis Chauvet vkms_config_encoder_detach_crtc(encoder->config, crtc->config); 439fad1138bSLouis Chauvet } 440fad1138bSLouis Chauvet 441fad1138bSLouis Chauvet static struct configfs_item_operations encoder_possible_crtcs_item_operations = { 442fad1138bSLouis Chauvet .allow_link = encoder_possible_crtcs_allow_link, 443fad1138bSLouis Chauvet .drop_link = encoder_possible_crtcs_drop_link, 444fad1138bSLouis Chauvet }; 445fad1138bSLouis Chauvet 446fad1138bSLouis Chauvet static const struct config_item_type encoder_possible_crtcs_group_type = { 447fad1138bSLouis Chauvet .ct_item_ops = &encoder_possible_crtcs_item_operations, 448fad1138bSLouis Chauvet .ct_owner = THIS_MODULE, 449fad1138bSLouis Chauvet }; 450fad1138bSLouis Chauvet 45167d8cf92SLouis Chauvet static void encoder_release(struct config_item *item) 45267d8cf92SLouis Chauvet { 45367d8cf92SLouis Chauvet struct vkms_configfs_encoder *encoder; 45467d8cf92SLouis Chauvet struct mutex *lock; 45567d8cf92SLouis Chauvet 45667d8cf92SLouis Chauvet encoder = encoder_item_to_vkms_configfs_encoder(item); 45767d8cf92SLouis Chauvet lock = &encoder->dev->lock; 45867d8cf92SLouis Chauvet 45967d8cf92SLouis Chauvet scoped_guard(mutex, lock) { 46067d8cf92SLouis Chauvet vkms_config_destroy_encoder(encoder->dev->config, encoder->config); 46167d8cf92SLouis Chauvet kfree(encoder); 46267d8cf92SLouis Chauvet } 46367d8cf92SLouis Chauvet } 46467d8cf92SLouis Chauvet 46567d8cf92SLouis Chauvet static struct configfs_item_operations encoder_item_operations = { 46667d8cf92SLouis Chauvet .release = &encoder_release, 46767d8cf92SLouis Chauvet }; 46867d8cf92SLouis Chauvet 46967d8cf92SLouis Chauvet static const struct config_item_type encoder_item_type = { 47067d8cf92SLouis Chauvet .ct_item_ops = &encoder_item_operations, 47167d8cf92SLouis Chauvet .ct_owner = THIS_MODULE, 47267d8cf92SLouis Chauvet }; 47367d8cf92SLouis Chauvet 47467d8cf92SLouis Chauvet static struct config_group *make_encoder_group(struct config_group *group, 47567d8cf92SLouis Chauvet const char *name) 47667d8cf92SLouis Chauvet { 47767d8cf92SLouis Chauvet struct vkms_configfs_device *dev; 47867d8cf92SLouis Chauvet struct vkms_configfs_encoder *encoder; 479*f9e46accSDan Carpenter int ret; 48067d8cf92SLouis Chauvet 48167d8cf92SLouis Chauvet dev = child_group_to_vkms_configfs_device(group); 48267d8cf92SLouis Chauvet 48367d8cf92SLouis Chauvet scoped_guard(mutex, &dev->lock) { 48467d8cf92SLouis Chauvet if (dev->enabled) 48567d8cf92SLouis Chauvet return ERR_PTR(-EBUSY); 48667d8cf92SLouis Chauvet 48767d8cf92SLouis Chauvet encoder = kzalloc(sizeof(*encoder), GFP_KERNEL); 48867d8cf92SLouis Chauvet if (!encoder) 48967d8cf92SLouis Chauvet return ERR_PTR(-ENOMEM); 49067d8cf92SLouis Chauvet 49167d8cf92SLouis Chauvet encoder->dev = dev; 49267d8cf92SLouis Chauvet 49367d8cf92SLouis Chauvet encoder->config = vkms_config_create_encoder(dev->config); 49467d8cf92SLouis Chauvet if (IS_ERR(encoder->config)) { 495*f9e46accSDan Carpenter ret = PTR_ERR(encoder->config); 49667d8cf92SLouis Chauvet kfree(encoder); 497*f9e46accSDan Carpenter return ERR_PTR(ret); 49867d8cf92SLouis Chauvet } 49967d8cf92SLouis Chauvet 50067d8cf92SLouis Chauvet config_group_init_type_name(&encoder->group, name, 50167d8cf92SLouis Chauvet &encoder_item_type); 502fad1138bSLouis Chauvet 503fad1138bSLouis Chauvet config_group_init_type_name(&encoder->possible_crtcs_group, 504fad1138bSLouis Chauvet "possible_crtcs", 505fad1138bSLouis Chauvet &encoder_possible_crtcs_group_type); 506fad1138bSLouis Chauvet configfs_add_default_group(&encoder->possible_crtcs_group, 507fad1138bSLouis Chauvet &encoder->group); 50867d8cf92SLouis Chauvet } 50967d8cf92SLouis Chauvet 51067d8cf92SLouis Chauvet return &encoder->group; 51167d8cf92SLouis Chauvet } 51267d8cf92SLouis Chauvet 51367d8cf92SLouis Chauvet static struct configfs_group_operations encoders_group_operations = { 51467d8cf92SLouis Chauvet .make_group = &make_encoder_group, 51567d8cf92SLouis Chauvet }; 51667d8cf92SLouis Chauvet 51767d8cf92SLouis Chauvet static const struct config_item_type encoder_group_type = { 51867d8cf92SLouis Chauvet .ct_group_ops = &encoders_group_operations, 51967d8cf92SLouis Chauvet .ct_owner = THIS_MODULE, 52067d8cf92SLouis Chauvet }; 52167d8cf92SLouis Chauvet 522f97180f0SJosé Expósito static ssize_t connector_status_show(struct config_item *item, char *page) 523f97180f0SJosé Expósito { 524f97180f0SJosé Expósito struct vkms_configfs_connector *connector; 525f97180f0SJosé Expósito enum drm_connector_status status; 526f97180f0SJosé Expósito 527f97180f0SJosé Expósito connector = connector_item_to_vkms_configfs_connector(item); 528f97180f0SJosé Expósito 529f97180f0SJosé Expósito scoped_guard(mutex, &connector->dev->lock) 530f97180f0SJosé Expósito status = vkms_config_connector_get_status(connector->config); 531f97180f0SJosé Expósito 532f97180f0SJosé Expósito return sprintf(page, "%u", status); 533f97180f0SJosé Expósito } 534f97180f0SJosé Expósito 535f97180f0SJosé Expósito static ssize_t connector_status_store(struct config_item *item, 536f97180f0SJosé Expósito const char *page, size_t count) 537f97180f0SJosé Expósito { 538f97180f0SJosé Expósito struct vkms_configfs_connector *connector; 539f97180f0SJosé Expósito enum drm_connector_status status; 540f97180f0SJosé Expósito 541f97180f0SJosé Expósito connector = connector_item_to_vkms_configfs_connector(item); 542f97180f0SJosé Expósito 543f97180f0SJosé Expósito if (kstrtouint(page, 10, &status)) 544f97180f0SJosé Expósito return -EINVAL; 545f97180f0SJosé Expósito 546f97180f0SJosé Expósito if (status != connector_status_connected && 547f97180f0SJosé Expósito status != connector_status_disconnected && 548f97180f0SJosé Expósito status != connector_status_unknown) 549f97180f0SJosé Expósito return -EINVAL; 550f97180f0SJosé Expósito 551f97180f0SJosé Expósito scoped_guard(mutex, &connector->dev->lock) { 552f97180f0SJosé Expósito vkms_config_connector_set_status(connector->config, status); 553f97180f0SJosé Expósito 554f97180f0SJosé Expósito if (connector->dev->enabled) 555f97180f0SJosé Expósito vkms_trigger_connector_hotplug(connector->dev->config->dev); 556f97180f0SJosé Expósito } 557f97180f0SJosé Expósito 558f97180f0SJosé Expósito return (ssize_t)count; 559f97180f0SJosé Expósito } 560f97180f0SJosé Expósito 561f97180f0SJosé Expósito CONFIGFS_ATTR(connector_, status); 562f97180f0SJosé Expósito 563f97180f0SJosé Expósito static struct configfs_attribute *connector_item_attrs[] = { 564f97180f0SJosé Expósito &connector_attr_status, 565f97180f0SJosé Expósito NULL, 566f97180f0SJosé Expósito }; 567f97180f0SJosé Expósito 568272acbcaSLouis Chauvet static void connector_release(struct config_item *item) 569272acbcaSLouis Chauvet { 570272acbcaSLouis Chauvet struct vkms_configfs_connector *connector; 571272acbcaSLouis Chauvet struct mutex *lock; 572272acbcaSLouis Chauvet 573272acbcaSLouis Chauvet connector = connector_item_to_vkms_configfs_connector(item); 574272acbcaSLouis Chauvet lock = &connector->dev->lock; 575272acbcaSLouis Chauvet 576272acbcaSLouis Chauvet scoped_guard(mutex, lock) { 577272acbcaSLouis Chauvet vkms_config_destroy_connector(connector->config); 578272acbcaSLouis Chauvet kfree(connector); 579272acbcaSLouis Chauvet } 580272acbcaSLouis Chauvet } 581272acbcaSLouis Chauvet 582272acbcaSLouis Chauvet static struct configfs_item_operations connector_item_operations = { 583272acbcaSLouis Chauvet .release = &connector_release, 584272acbcaSLouis Chauvet }; 585272acbcaSLouis Chauvet 586272acbcaSLouis Chauvet static const struct config_item_type connector_item_type = { 587f97180f0SJosé Expósito .ct_attrs = connector_item_attrs, 588272acbcaSLouis Chauvet .ct_item_ops = &connector_item_operations, 589272acbcaSLouis Chauvet .ct_owner = THIS_MODULE, 590272acbcaSLouis Chauvet }; 591272acbcaSLouis Chauvet 59264229b84SLouis Chauvet static int connector_possible_encoders_allow_link(struct config_item *src, 59364229b84SLouis Chauvet struct config_item *target) 59464229b84SLouis Chauvet { 59564229b84SLouis Chauvet struct vkms_configfs_connector *connector; 59664229b84SLouis Chauvet struct vkms_configfs_encoder *encoder; 59764229b84SLouis Chauvet int ret; 59864229b84SLouis Chauvet 59964229b84SLouis Chauvet if (target->ci_type != &encoder_item_type) 60064229b84SLouis Chauvet return -EINVAL; 60164229b84SLouis Chauvet 60264229b84SLouis Chauvet connector = connector_possible_encoders_item_to_vkms_configfs_connector(src); 60364229b84SLouis Chauvet encoder = encoder_item_to_vkms_configfs_encoder(target); 60464229b84SLouis Chauvet 60564229b84SLouis Chauvet scoped_guard(mutex, &connector->dev->lock) { 60664229b84SLouis Chauvet if (connector->dev->enabled) 60764229b84SLouis Chauvet return -EBUSY; 60864229b84SLouis Chauvet 60964229b84SLouis Chauvet ret = vkms_config_connector_attach_encoder(connector->config, 61064229b84SLouis Chauvet encoder->config); 61164229b84SLouis Chauvet } 61264229b84SLouis Chauvet 61364229b84SLouis Chauvet return ret; 61464229b84SLouis Chauvet } 61564229b84SLouis Chauvet 61664229b84SLouis Chauvet static void connector_possible_encoders_drop_link(struct config_item *src, 61764229b84SLouis Chauvet struct config_item *target) 61864229b84SLouis Chauvet { 61964229b84SLouis Chauvet struct vkms_configfs_connector *connector; 62064229b84SLouis Chauvet struct vkms_configfs_encoder *encoder; 62164229b84SLouis Chauvet 62264229b84SLouis Chauvet connector = connector_possible_encoders_item_to_vkms_configfs_connector(src); 62364229b84SLouis Chauvet encoder = encoder_item_to_vkms_configfs_encoder(target); 62464229b84SLouis Chauvet 62564229b84SLouis Chauvet scoped_guard(mutex, &connector->dev->lock) { 62664229b84SLouis Chauvet vkms_config_connector_detach_encoder(connector->config, 62764229b84SLouis Chauvet encoder->config); 62864229b84SLouis Chauvet } 62964229b84SLouis Chauvet } 63064229b84SLouis Chauvet 63164229b84SLouis Chauvet static struct configfs_item_operations connector_possible_encoders_item_operations = { 63264229b84SLouis Chauvet .allow_link = connector_possible_encoders_allow_link, 63364229b84SLouis Chauvet .drop_link = connector_possible_encoders_drop_link, 63464229b84SLouis Chauvet }; 63564229b84SLouis Chauvet 63664229b84SLouis Chauvet static const struct config_item_type connector_possible_encoders_group_type = { 63764229b84SLouis Chauvet .ct_item_ops = &connector_possible_encoders_item_operations, 63864229b84SLouis Chauvet .ct_owner = THIS_MODULE, 63964229b84SLouis Chauvet }; 64064229b84SLouis Chauvet 641272acbcaSLouis Chauvet static struct config_group *make_connector_group(struct config_group *group, 642272acbcaSLouis Chauvet const char *name) 643272acbcaSLouis Chauvet { 644272acbcaSLouis Chauvet struct vkms_configfs_device *dev; 645272acbcaSLouis Chauvet struct vkms_configfs_connector *connector; 646*f9e46accSDan Carpenter int ret; 647272acbcaSLouis Chauvet 648272acbcaSLouis Chauvet dev = child_group_to_vkms_configfs_device(group); 649272acbcaSLouis Chauvet 650272acbcaSLouis Chauvet scoped_guard(mutex, &dev->lock) { 651272acbcaSLouis Chauvet if (dev->enabled) 652272acbcaSLouis Chauvet return ERR_PTR(-EBUSY); 653272acbcaSLouis Chauvet 654272acbcaSLouis Chauvet connector = kzalloc(sizeof(*connector), GFP_KERNEL); 655272acbcaSLouis Chauvet if (!connector) 656272acbcaSLouis Chauvet return ERR_PTR(-ENOMEM); 657272acbcaSLouis Chauvet 658272acbcaSLouis Chauvet connector->dev = dev; 659272acbcaSLouis Chauvet 660272acbcaSLouis Chauvet connector->config = vkms_config_create_connector(dev->config); 661272acbcaSLouis Chauvet if (IS_ERR(connector->config)) { 662*f9e46accSDan Carpenter ret = PTR_ERR(connector->config); 663272acbcaSLouis Chauvet kfree(connector); 664*f9e46accSDan Carpenter return ERR_PTR(ret); 665272acbcaSLouis Chauvet } 666272acbcaSLouis Chauvet 667272acbcaSLouis Chauvet config_group_init_type_name(&connector->group, name, 668272acbcaSLouis Chauvet &connector_item_type); 66964229b84SLouis Chauvet 67064229b84SLouis Chauvet config_group_init_type_name(&connector->possible_encoders_group, 67164229b84SLouis Chauvet "possible_encoders", 67264229b84SLouis Chauvet &connector_possible_encoders_group_type); 67364229b84SLouis Chauvet configfs_add_default_group(&connector->possible_encoders_group, 67464229b84SLouis Chauvet &connector->group); 675272acbcaSLouis Chauvet } 676272acbcaSLouis Chauvet 677272acbcaSLouis Chauvet return &connector->group; 678272acbcaSLouis Chauvet } 679272acbcaSLouis Chauvet 680272acbcaSLouis Chauvet static struct configfs_group_operations connectors_group_operations = { 681272acbcaSLouis Chauvet .make_group = &make_connector_group, 682272acbcaSLouis Chauvet }; 683272acbcaSLouis Chauvet 684272acbcaSLouis Chauvet static const struct config_item_type connector_group_type = { 685272acbcaSLouis Chauvet .ct_group_ops = &connectors_group_operations, 686272acbcaSLouis Chauvet .ct_owner = THIS_MODULE, 687272acbcaSLouis Chauvet }; 688272acbcaSLouis Chauvet 68913fc9b97SLouis Chauvet static ssize_t device_enabled_show(struct config_item *item, char *page) 69013fc9b97SLouis Chauvet { 69113fc9b97SLouis Chauvet struct vkms_configfs_device *dev; 69213fc9b97SLouis Chauvet bool enabled; 69313fc9b97SLouis Chauvet 69413fc9b97SLouis Chauvet dev = device_item_to_vkms_configfs_device(item); 69513fc9b97SLouis Chauvet 69613fc9b97SLouis Chauvet scoped_guard(mutex, &dev->lock) 69713fc9b97SLouis Chauvet enabled = dev->enabled; 69813fc9b97SLouis Chauvet 69913fc9b97SLouis Chauvet return sprintf(page, "%d\n", enabled); 70013fc9b97SLouis Chauvet } 70113fc9b97SLouis Chauvet 70213fc9b97SLouis Chauvet static ssize_t device_enabled_store(struct config_item *item, const char *page, 70313fc9b97SLouis Chauvet size_t count) 70413fc9b97SLouis Chauvet { 70513fc9b97SLouis Chauvet struct vkms_configfs_device *dev; 70613fc9b97SLouis Chauvet bool enabled; 70713fc9b97SLouis Chauvet int ret = 0; 70813fc9b97SLouis Chauvet 70913fc9b97SLouis Chauvet dev = device_item_to_vkms_configfs_device(item); 71013fc9b97SLouis Chauvet 71113fc9b97SLouis Chauvet if (kstrtobool(page, &enabled)) 71213fc9b97SLouis Chauvet return -EINVAL; 71313fc9b97SLouis Chauvet 71413fc9b97SLouis Chauvet scoped_guard(mutex, &dev->lock) { 71513fc9b97SLouis Chauvet if (!dev->enabled && enabled) { 71613fc9b97SLouis Chauvet if (!vkms_config_is_valid(dev->config)) 71713fc9b97SLouis Chauvet return -EINVAL; 71813fc9b97SLouis Chauvet 71913fc9b97SLouis Chauvet ret = vkms_create(dev->config); 72013fc9b97SLouis Chauvet if (ret) 72113fc9b97SLouis Chauvet return ret; 72213fc9b97SLouis Chauvet } else if (dev->enabled && !enabled) { 72313fc9b97SLouis Chauvet vkms_destroy(dev->config); 72413fc9b97SLouis Chauvet } 72513fc9b97SLouis Chauvet 72613fc9b97SLouis Chauvet dev->enabled = enabled; 72713fc9b97SLouis Chauvet } 72813fc9b97SLouis Chauvet 72913fc9b97SLouis Chauvet return (ssize_t)count; 73013fc9b97SLouis Chauvet } 73113fc9b97SLouis Chauvet 73213fc9b97SLouis Chauvet CONFIGFS_ATTR(device_, enabled); 73313fc9b97SLouis Chauvet 73413fc9b97SLouis Chauvet static struct configfs_attribute *device_item_attrs[] = { 73513fc9b97SLouis Chauvet &device_attr_enabled, 73613fc9b97SLouis Chauvet NULL, 73713fc9b97SLouis Chauvet }; 73813fc9b97SLouis Chauvet 73913fc9b97SLouis Chauvet static void device_release(struct config_item *item) 74013fc9b97SLouis Chauvet { 74113fc9b97SLouis Chauvet struct vkms_configfs_device *dev; 74213fc9b97SLouis Chauvet 74313fc9b97SLouis Chauvet dev = device_item_to_vkms_configfs_device(item); 74413fc9b97SLouis Chauvet 74513fc9b97SLouis Chauvet if (dev->enabled) 74613fc9b97SLouis Chauvet vkms_destroy(dev->config); 74713fc9b97SLouis Chauvet 74813fc9b97SLouis Chauvet mutex_destroy(&dev->lock); 74913fc9b97SLouis Chauvet vkms_config_destroy(dev->config); 75013fc9b97SLouis Chauvet kfree(dev); 75113fc9b97SLouis Chauvet } 75213fc9b97SLouis Chauvet 75313fc9b97SLouis Chauvet static struct configfs_item_operations device_item_operations = { 75413fc9b97SLouis Chauvet .release = &device_release, 75513fc9b97SLouis Chauvet }; 75613fc9b97SLouis Chauvet 75713fc9b97SLouis Chauvet static const struct config_item_type device_item_type = { 75813fc9b97SLouis Chauvet .ct_attrs = device_item_attrs, 75913fc9b97SLouis Chauvet .ct_item_ops = &device_item_operations, 76013fc9b97SLouis Chauvet .ct_owner = THIS_MODULE, 76113fc9b97SLouis Chauvet }; 76213fc9b97SLouis Chauvet 76313fc9b97SLouis Chauvet static struct config_group *make_device_group(struct config_group *group, 76413fc9b97SLouis Chauvet const char *name) 76513fc9b97SLouis Chauvet { 76613fc9b97SLouis Chauvet struct vkms_configfs_device *dev; 767*f9e46accSDan Carpenter int ret; 76813fc9b97SLouis Chauvet 76913fc9b97SLouis Chauvet if (strcmp(name, DEFAULT_DEVICE_NAME) == 0) 77013fc9b97SLouis Chauvet return ERR_PTR(-EINVAL); 77113fc9b97SLouis Chauvet 77213fc9b97SLouis Chauvet dev = kzalloc(sizeof(*dev), GFP_KERNEL); 77313fc9b97SLouis Chauvet if (!dev) 77413fc9b97SLouis Chauvet return ERR_PTR(-ENOMEM); 77513fc9b97SLouis Chauvet 77613fc9b97SLouis Chauvet dev->config = vkms_config_create(name); 77713fc9b97SLouis Chauvet if (IS_ERR(dev->config)) { 778*f9e46accSDan Carpenter ret = PTR_ERR(dev->config); 77913fc9b97SLouis Chauvet kfree(dev); 780*f9e46accSDan Carpenter return ERR_PTR(ret); 78113fc9b97SLouis Chauvet } 78213fc9b97SLouis Chauvet 78313fc9b97SLouis Chauvet config_group_init_type_name(&dev->group, name, &device_item_type); 78413fc9b97SLouis Chauvet mutex_init(&dev->lock); 78513fc9b97SLouis Chauvet 7862f1734baSLouis Chauvet config_group_init_type_name(&dev->planes_group, "planes", 7872f1734baSLouis Chauvet &plane_group_type); 7882f1734baSLouis Chauvet configfs_add_default_group(&dev->planes_group, &dev->group); 7892f1734baSLouis Chauvet 7903e4d5b30SLouis Chauvet config_group_init_type_name(&dev->crtcs_group, "crtcs", 7913e4d5b30SLouis Chauvet &crtc_group_type); 7923e4d5b30SLouis Chauvet configfs_add_default_group(&dev->crtcs_group, &dev->group); 7933e4d5b30SLouis Chauvet 79467d8cf92SLouis Chauvet config_group_init_type_name(&dev->encoders_group, "encoders", 79567d8cf92SLouis Chauvet &encoder_group_type); 79667d8cf92SLouis Chauvet configfs_add_default_group(&dev->encoders_group, &dev->group); 79767d8cf92SLouis Chauvet 798272acbcaSLouis Chauvet config_group_init_type_name(&dev->connectors_group, "connectors", 799272acbcaSLouis Chauvet &connector_group_type); 800272acbcaSLouis Chauvet configfs_add_default_group(&dev->connectors_group, &dev->group); 801272acbcaSLouis Chauvet 80213fc9b97SLouis Chauvet return &dev->group; 80313fc9b97SLouis Chauvet } 80413fc9b97SLouis Chauvet 80513fc9b97SLouis Chauvet static struct configfs_group_operations device_group_ops = { 80613fc9b97SLouis Chauvet .make_group = &make_device_group, 80713fc9b97SLouis Chauvet }; 80813fc9b97SLouis Chauvet 80913fc9b97SLouis Chauvet static const struct config_item_type device_group_type = { 81013fc9b97SLouis Chauvet .ct_group_ops = &device_group_ops, 81113fc9b97SLouis Chauvet .ct_owner = THIS_MODULE, 81213fc9b97SLouis Chauvet }; 81313fc9b97SLouis Chauvet 81413fc9b97SLouis Chauvet static struct configfs_subsystem vkms_subsys = { 81513fc9b97SLouis Chauvet .su_group = { 81613fc9b97SLouis Chauvet .cg_item = { 81713fc9b97SLouis Chauvet .ci_name = "vkms", 81813fc9b97SLouis Chauvet .ci_type = &device_group_type, 81913fc9b97SLouis Chauvet }, 82013fc9b97SLouis Chauvet }, 82113fc9b97SLouis Chauvet .su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex), 82213fc9b97SLouis Chauvet }; 82313fc9b97SLouis Chauvet 82413fc9b97SLouis Chauvet int vkms_configfs_register(void) 82513fc9b97SLouis Chauvet { 82613fc9b97SLouis Chauvet int ret; 82713fc9b97SLouis Chauvet 82813fc9b97SLouis Chauvet if (is_configfs_registered) 82913fc9b97SLouis Chauvet return 0; 83013fc9b97SLouis Chauvet 83113fc9b97SLouis Chauvet config_group_init(&vkms_subsys.su_group); 83213fc9b97SLouis Chauvet ret = configfs_register_subsystem(&vkms_subsys); 83313fc9b97SLouis Chauvet 83413fc9b97SLouis Chauvet is_configfs_registered = ret == 0; 83513fc9b97SLouis Chauvet 83613fc9b97SLouis Chauvet return ret; 83713fc9b97SLouis Chauvet } 83813fc9b97SLouis Chauvet 83913fc9b97SLouis Chauvet void vkms_configfs_unregister(void) 84013fc9b97SLouis Chauvet { 84113fc9b97SLouis Chauvet if (is_configfs_registered) 84213fc9b97SLouis Chauvet configfs_unregister_subsystem(&vkms_subsys); 84313fc9b97SLouis Chauvet } 844