1b2765275SChristian Gromm // SPDX-License-Identifier: GPL-2.0 2b2765275SChristian Gromm /* 3b2765275SChristian Gromm * configfs.c - Implementation of configfs interface to the driver stack 4b2765275SChristian Gromm * 5b2765275SChristian Gromm * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG 6b2765275SChristian Gromm */ 7b2765275SChristian Gromm 8b2765275SChristian Gromm #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9b2765275SChristian Gromm #include <linux/module.h> 10b2765275SChristian Gromm #include <linux/slab.h> 11b2765275SChristian Gromm #include <linux/init.h> 12b2765275SChristian Gromm #include <linux/configfs.h> 13b2765275SChristian Gromm #include <linux/most.h> 14b2765275SChristian Gromm 15b2765275SChristian Gromm #define MAX_STRING_SIZE 80 16b2765275SChristian Gromm 17b2765275SChristian Gromm struct mdev_link { 18b2765275SChristian Gromm struct config_item item; 19b2765275SChristian Gromm struct list_head list; 20b2765275SChristian Gromm bool create_link; 21b2765275SChristian Gromm bool destroy_link; 22b2765275SChristian Gromm u16 num_buffers; 23b2765275SChristian Gromm u16 buffer_size; 24b2765275SChristian Gromm u16 subbuffer_size; 25b2765275SChristian Gromm u16 packets_per_xact; 26b2765275SChristian Gromm u16 dbr_size; 27b2765275SChristian Gromm char datatype[MAX_STRING_SIZE]; 28b2765275SChristian Gromm char direction[MAX_STRING_SIZE]; 29b2765275SChristian Gromm char name[MAX_STRING_SIZE]; 30b2765275SChristian Gromm char device[MAX_STRING_SIZE]; 31b2765275SChristian Gromm char channel[MAX_STRING_SIZE]; 32b2765275SChristian Gromm char comp[MAX_STRING_SIZE]; 33b2765275SChristian Gromm char comp_params[MAX_STRING_SIZE]; 34b2765275SChristian Gromm }; 35b2765275SChristian Gromm 36b2765275SChristian Gromm static struct list_head mdev_link_list; 37b2765275SChristian Gromm 38b2765275SChristian Gromm static int set_cfg_buffer_size(struct mdev_link *link) 39b2765275SChristian Gromm { 40b2765275SChristian Gromm return most_set_cfg_buffer_size(link->device, link->channel, 41b2765275SChristian Gromm link->buffer_size); 42b2765275SChristian Gromm } 43b2765275SChristian Gromm 44b2765275SChristian Gromm static int set_cfg_subbuffer_size(struct mdev_link *link) 45b2765275SChristian Gromm { 46b2765275SChristian Gromm return most_set_cfg_subbuffer_size(link->device, link->channel, 47b2765275SChristian Gromm link->subbuffer_size); 48b2765275SChristian Gromm } 49b2765275SChristian Gromm 50b2765275SChristian Gromm static int set_cfg_dbr_size(struct mdev_link *link) 51b2765275SChristian Gromm { 52b2765275SChristian Gromm return most_set_cfg_dbr_size(link->device, link->channel, 53b2765275SChristian Gromm link->dbr_size); 54b2765275SChristian Gromm } 55b2765275SChristian Gromm 56b2765275SChristian Gromm static int set_cfg_num_buffers(struct mdev_link *link) 57b2765275SChristian Gromm { 58b2765275SChristian Gromm return most_set_cfg_num_buffers(link->device, link->channel, 59b2765275SChristian Gromm link->num_buffers); 60b2765275SChristian Gromm } 61b2765275SChristian Gromm 62b2765275SChristian Gromm static int set_cfg_packets_xact(struct mdev_link *link) 63b2765275SChristian Gromm { 64b2765275SChristian Gromm return most_set_cfg_packets_xact(link->device, link->channel, 65b2765275SChristian Gromm link->packets_per_xact); 66b2765275SChristian Gromm } 67b2765275SChristian Gromm 68b2765275SChristian Gromm static int set_cfg_direction(struct mdev_link *link) 69b2765275SChristian Gromm { 70b2765275SChristian Gromm return most_set_cfg_direction(link->device, link->channel, 71b2765275SChristian Gromm link->direction); 72b2765275SChristian Gromm } 73b2765275SChristian Gromm 74b2765275SChristian Gromm static int set_cfg_datatype(struct mdev_link *link) 75b2765275SChristian Gromm { 76b2765275SChristian Gromm return most_set_cfg_datatype(link->device, link->channel, 77b2765275SChristian Gromm link->datatype); 78b2765275SChristian Gromm } 79b2765275SChristian Gromm 80b2765275SChristian Gromm static int (*set_config_val[])(struct mdev_link *link) = { 81b2765275SChristian Gromm set_cfg_buffer_size, 82b2765275SChristian Gromm set_cfg_subbuffer_size, 83b2765275SChristian Gromm set_cfg_dbr_size, 84b2765275SChristian Gromm set_cfg_num_buffers, 85b2765275SChristian Gromm set_cfg_packets_xact, 86b2765275SChristian Gromm set_cfg_direction, 87b2765275SChristian Gromm set_cfg_datatype, 88b2765275SChristian Gromm }; 89b2765275SChristian Gromm 90b2765275SChristian Gromm static struct mdev_link *to_mdev_link(struct config_item *item) 91b2765275SChristian Gromm { 92b2765275SChristian Gromm return container_of(item, struct mdev_link, item); 93b2765275SChristian Gromm } 94b2765275SChristian Gromm 95b2765275SChristian Gromm static int set_config_and_add_link(struct mdev_link *mdev_link) 96b2765275SChristian Gromm { 97b2765275SChristian Gromm int i; 98b2765275SChristian Gromm int ret; 99b2765275SChristian Gromm 100b2765275SChristian Gromm for (i = 0; i < ARRAY_SIZE(set_config_val); i++) { 101b2765275SChristian Gromm ret = set_config_val[i](mdev_link); 102b2765275SChristian Gromm if (ret < 0 && ret != -ENODEV) { 103b2765275SChristian Gromm pr_err("Config failed\n"); 104b2765275SChristian Gromm return ret; 105b2765275SChristian Gromm } 106b2765275SChristian Gromm } 107b2765275SChristian Gromm 108b2765275SChristian Gromm return most_add_link(mdev_link->device, mdev_link->channel, 109b2765275SChristian Gromm mdev_link->comp, mdev_link->name, 110b2765275SChristian Gromm mdev_link->comp_params); 111b2765275SChristian Gromm } 112b2765275SChristian Gromm 113b2765275SChristian Gromm static ssize_t mdev_link_create_link_store(struct config_item *item, 114b2765275SChristian Gromm const char *page, size_t count) 115b2765275SChristian Gromm { 116b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 117b2765275SChristian Gromm bool tmp; 118b2765275SChristian Gromm int ret; 119b2765275SChristian Gromm 120b2765275SChristian Gromm ret = kstrtobool(page, &tmp); 121b2765275SChristian Gromm if (ret) 122b2765275SChristian Gromm return ret; 123b2765275SChristian Gromm if (!tmp) 124b2765275SChristian Gromm return count; 125b2765275SChristian Gromm ret = set_config_and_add_link(mdev_link); 126b2765275SChristian Gromm if (ret && ret != -ENODEV) 127b2765275SChristian Gromm return ret; 128b2765275SChristian Gromm list_add_tail(&mdev_link->list, &mdev_link_list); 129b2765275SChristian Gromm mdev_link->create_link = tmp; 130b2765275SChristian Gromm mdev_link->destroy_link = false; 131b2765275SChristian Gromm 132b2765275SChristian Gromm return count; 133b2765275SChristian Gromm } 134b2765275SChristian Gromm 135b2765275SChristian Gromm static ssize_t mdev_link_destroy_link_store(struct config_item *item, 136b2765275SChristian Gromm const char *page, size_t count) 137b2765275SChristian Gromm { 138b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 139b2765275SChristian Gromm bool tmp; 140b2765275SChristian Gromm int ret; 141b2765275SChristian Gromm 142b2765275SChristian Gromm ret = kstrtobool(page, &tmp); 143b2765275SChristian Gromm if (ret) 144b2765275SChristian Gromm return ret; 145b2765275SChristian Gromm if (!tmp) 146b2765275SChristian Gromm return count; 147b2765275SChristian Gromm 148b2765275SChristian Gromm ret = most_remove_link(mdev_link->device, mdev_link->channel, 149b2765275SChristian Gromm mdev_link->comp); 150b2765275SChristian Gromm if (ret) 151b2765275SChristian Gromm return ret; 152b2765275SChristian Gromm if (!list_empty(&mdev_link_list)) 153b2765275SChristian Gromm list_del(&mdev_link->list); 154b2765275SChristian Gromm 155b2765275SChristian Gromm mdev_link->destroy_link = tmp; 156b2765275SChristian Gromm 157b2765275SChristian Gromm return count; 158b2765275SChristian Gromm } 159b2765275SChristian Gromm 160b2765275SChristian Gromm static ssize_t mdev_link_direction_show(struct config_item *item, char *page) 161b2765275SChristian Gromm { 162b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->direction); 163b2765275SChristian Gromm } 164b2765275SChristian Gromm 165b2765275SChristian Gromm static ssize_t mdev_link_direction_store(struct config_item *item, 166b2765275SChristian Gromm const char *page, size_t count) 167b2765275SChristian Gromm { 168b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 169b2765275SChristian Gromm 170b2765275SChristian Gromm if (!sysfs_streq(page, "dir_rx") && !sysfs_streq(page, "rx") && 171b2765275SChristian Gromm !sysfs_streq(page, "dir_tx") && !sysfs_streq(page, "tx")) 172b2765275SChristian Gromm return -EINVAL; 173b2765275SChristian Gromm strcpy(mdev_link->direction, page); 174b2765275SChristian Gromm strim(mdev_link->direction); 175b2765275SChristian Gromm return count; 176b2765275SChristian Gromm } 177b2765275SChristian Gromm 178b2765275SChristian Gromm static ssize_t mdev_link_datatype_show(struct config_item *item, char *page) 179b2765275SChristian Gromm { 180b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->datatype); 181b2765275SChristian Gromm } 182b2765275SChristian Gromm 183b2765275SChristian Gromm static ssize_t mdev_link_datatype_store(struct config_item *item, 184b2765275SChristian Gromm const char *page, size_t count) 185b2765275SChristian Gromm { 186b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 187b2765275SChristian Gromm 188b2765275SChristian Gromm if (!sysfs_streq(page, "control") && !sysfs_streq(page, "async") && 189b2765275SChristian Gromm !sysfs_streq(page, "sync") && !sysfs_streq(page, "isoc") && 190b2765275SChristian Gromm !sysfs_streq(page, "isoc_avp")) 191b2765275SChristian Gromm return -EINVAL; 192b2765275SChristian Gromm strcpy(mdev_link->datatype, page); 193b2765275SChristian Gromm strim(mdev_link->datatype); 194b2765275SChristian Gromm return count; 195b2765275SChristian Gromm } 196b2765275SChristian Gromm 197b2765275SChristian Gromm static ssize_t mdev_link_device_show(struct config_item *item, char *page) 198b2765275SChristian Gromm { 199b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->device); 200b2765275SChristian Gromm } 201b2765275SChristian Gromm 202b2765275SChristian Gromm static ssize_t mdev_link_device_store(struct config_item *item, 203b2765275SChristian Gromm const char *page, size_t count) 204b2765275SChristian Gromm { 205b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 206b2765275SChristian Gromm 207b2765275SChristian Gromm strlcpy(mdev_link->device, page, sizeof(mdev_link->device)); 208b2765275SChristian Gromm strim(mdev_link->device); 209b2765275SChristian Gromm return count; 210b2765275SChristian Gromm } 211b2765275SChristian Gromm 212b2765275SChristian Gromm static ssize_t mdev_link_channel_show(struct config_item *item, char *page) 213b2765275SChristian Gromm { 214b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->channel); 215b2765275SChristian Gromm } 216b2765275SChristian Gromm 217b2765275SChristian Gromm static ssize_t mdev_link_channel_store(struct config_item *item, 218b2765275SChristian Gromm const char *page, size_t count) 219b2765275SChristian Gromm { 220b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 221b2765275SChristian Gromm 222b2765275SChristian Gromm strlcpy(mdev_link->channel, page, sizeof(mdev_link->channel)); 223b2765275SChristian Gromm strim(mdev_link->channel); 224b2765275SChristian Gromm return count; 225b2765275SChristian Gromm } 226b2765275SChristian Gromm 227b2765275SChristian Gromm static ssize_t mdev_link_comp_show(struct config_item *item, char *page) 228b2765275SChristian Gromm { 229b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->comp); 230b2765275SChristian Gromm } 231b2765275SChristian Gromm 232b2765275SChristian Gromm static ssize_t mdev_link_comp_store(struct config_item *item, 233b2765275SChristian Gromm const char *page, size_t count) 234b2765275SChristian Gromm { 235b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 236b2765275SChristian Gromm 237b2765275SChristian Gromm strlcpy(mdev_link->comp, page, sizeof(mdev_link->comp)); 238b2765275SChristian Gromm strim(mdev_link->comp); 239b2765275SChristian Gromm return count; 240b2765275SChristian Gromm } 241b2765275SChristian Gromm 242b2765275SChristian Gromm static ssize_t mdev_link_comp_params_show(struct config_item *item, char *page) 243b2765275SChristian Gromm { 244b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%s\n", 245b2765275SChristian Gromm to_mdev_link(item)->comp_params); 246b2765275SChristian Gromm } 247b2765275SChristian Gromm 248b2765275SChristian Gromm static ssize_t mdev_link_comp_params_store(struct config_item *item, 249b2765275SChristian Gromm const char *page, size_t count) 250b2765275SChristian Gromm { 251b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 252b2765275SChristian Gromm 253b2765275SChristian Gromm strlcpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); 254b2765275SChristian Gromm strim(mdev_link->comp_params); 255b2765275SChristian Gromm return count; 256b2765275SChristian Gromm } 257b2765275SChristian Gromm 258b2765275SChristian Gromm static ssize_t mdev_link_num_buffers_show(struct config_item *item, char *page) 259b2765275SChristian Gromm { 260b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%d\n", 261b2765275SChristian Gromm to_mdev_link(item)->num_buffers); 262b2765275SChristian Gromm } 263b2765275SChristian Gromm 264b2765275SChristian Gromm static ssize_t mdev_link_num_buffers_store(struct config_item *item, 265b2765275SChristian Gromm const char *page, size_t count) 266b2765275SChristian Gromm { 267b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 268b2765275SChristian Gromm int ret; 269b2765275SChristian Gromm 270b2765275SChristian Gromm ret = kstrtou16(page, 0, &mdev_link->num_buffers); 271b2765275SChristian Gromm if (ret) 272b2765275SChristian Gromm return ret; 273b2765275SChristian Gromm return count; 274b2765275SChristian Gromm } 275b2765275SChristian Gromm 276b2765275SChristian Gromm static ssize_t mdev_link_buffer_size_show(struct config_item *item, char *page) 277b2765275SChristian Gromm { 278b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%d\n", 279b2765275SChristian Gromm to_mdev_link(item)->buffer_size); 280b2765275SChristian Gromm } 281b2765275SChristian Gromm 282b2765275SChristian Gromm static ssize_t mdev_link_buffer_size_store(struct config_item *item, 283b2765275SChristian Gromm const char *page, size_t count) 284b2765275SChristian Gromm { 285b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 286b2765275SChristian Gromm int ret; 287b2765275SChristian Gromm 288b2765275SChristian Gromm ret = kstrtou16(page, 0, &mdev_link->buffer_size); 289b2765275SChristian Gromm if (ret) 290b2765275SChristian Gromm return ret; 291b2765275SChristian Gromm return count; 292b2765275SChristian Gromm } 293b2765275SChristian Gromm 294b2765275SChristian Gromm static ssize_t mdev_link_subbuffer_size_show(struct config_item *item, 295b2765275SChristian Gromm char *page) 296b2765275SChristian Gromm { 297b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%d\n", 298b2765275SChristian Gromm to_mdev_link(item)->subbuffer_size); 299b2765275SChristian Gromm } 300b2765275SChristian Gromm 301b2765275SChristian Gromm static ssize_t mdev_link_subbuffer_size_store(struct config_item *item, 302b2765275SChristian Gromm const char *page, size_t count) 303b2765275SChristian Gromm { 304b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 305b2765275SChristian Gromm int ret; 306b2765275SChristian Gromm 307b2765275SChristian Gromm ret = kstrtou16(page, 0, &mdev_link->subbuffer_size); 308b2765275SChristian Gromm if (ret) 309b2765275SChristian Gromm return ret; 310b2765275SChristian Gromm return count; 311b2765275SChristian Gromm } 312b2765275SChristian Gromm 313b2765275SChristian Gromm static ssize_t mdev_link_packets_per_xact_show(struct config_item *item, 314b2765275SChristian Gromm char *page) 315b2765275SChristian Gromm { 316b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%d\n", 317b2765275SChristian Gromm to_mdev_link(item)->packets_per_xact); 318b2765275SChristian Gromm } 319b2765275SChristian Gromm 320b2765275SChristian Gromm static ssize_t mdev_link_packets_per_xact_store(struct config_item *item, 321b2765275SChristian Gromm const char *page, size_t count) 322b2765275SChristian Gromm { 323b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 324b2765275SChristian Gromm int ret; 325b2765275SChristian Gromm 326b2765275SChristian Gromm ret = kstrtou16(page, 0, &mdev_link->packets_per_xact); 327b2765275SChristian Gromm if (ret) 328b2765275SChristian Gromm return ret; 329b2765275SChristian Gromm return count; 330b2765275SChristian Gromm } 331b2765275SChristian Gromm 332b2765275SChristian Gromm static ssize_t mdev_link_dbr_size_show(struct config_item *item, char *page) 333b2765275SChristian Gromm { 334b2765275SChristian Gromm return snprintf(page, PAGE_SIZE, "%d\n", to_mdev_link(item)->dbr_size); 335b2765275SChristian Gromm } 336b2765275SChristian Gromm 337b2765275SChristian Gromm static ssize_t mdev_link_dbr_size_store(struct config_item *item, 338b2765275SChristian Gromm const char *page, size_t count) 339b2765275SChristian Gromm { 340b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 341b2765275SChristian Gromm int ret; 342b2765275SChristian Gromm 343b2765275SChristian Gromm ret = kstrtou16(page, 0, &mdev_link->dbr_size); 344b2765275SChristian Gromm if (ret) 345b2765275SChristian Gromm return ret; 346b2765275SChristian Gromm return count; 347b2765275SChristian Gromm } 348b2765275SChristian Gromm 349b2765275SChristian Gromm CONFIGFS_ATTR_WO(mdev_link_, create_link); 350b2765275SChristian Gromm CONFIGFS_ATTR_WO(mdev_link_, destroy_link); 351b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, device); 352b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, channel); 353b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, comp); 354b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, comp_params); 355b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, num_buffers); 356b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, buffer_size); 357b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, subbuffer_size); 358b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, packets_per_xact); 359b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, datatype); 360b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, direction); 361b2765275SChristian Gromm CONFIGFS_ATTR(mdev_link_, dbr_size); 362b2765275SChristian Gromm 363b2765275SChristian Gromm static struct configfs_attribute *mdev_link_attrs[] = { 364b2765275SChristian Gromm &mdev_link_attr_create_link, 365b2765275SChristian Gromm &mdev_link_attr_destroy_link, 366b2765275SChristian Gromm &mdev_link_attr_device, 367b2765275SChristian Gromm &mdev_link_attr_channel, 368b2765275SChristian Gromm &mdev_link_attr_comp, 369b2765275SChristian Gromm &mdev_link_attr_comp_params, 370b2765275SChristian Gromm &mdev_link_attr_num_buffers, 371b2765275SChristian Gromm &mdev_link_attr_buffer_size, 372b2765275SChristian Gromm &mdev_link_attr_subbuffer_size, 373b2765275SChristian Gromm &mdev_link_attr_packets_per_xact, 374b2765275SChristian Gromm &mdev_link_attr_datatype, 375b2765275SChristian Gromm &mdev_link_attr_direction, 376b2765275SChristian Gromm &mdev_link_attr_dbr_size, 377b2765275SChristian Gromm NULL, 378b2765275SChristian Gromm }; 379b2765275SChristian Gromm 380b2765275SChristian Gromm static void mdev_link_release(struct config_item *item) 381b2765275SChristian Gromm { 382b2765275SChristian Gromm struct mdev_link *mdev_link = to_mdev_link(item); 383b2765275SChristian Gromm int ret; 384b2765275SChristian Gromm 385b2765275SChristian Gromm if (mdev_link->destroy_link) 386b2765275SChristian Gromm goto free_item; 387b2765275SChristian Gromm 388b2765275SChristian Gromm ret = most_remove_link(mdev_link->device, mdev_link->channel, 389b2765275SChristian Gromm mdev_link->comp); 390b2765275SChristian Gromm if (ret) { 391b2765275SChristian Gromm pr_err("Removing link failed.\n"); 392b2765275SChristian Gromm goto free_item; 393b2765275SChristian Gromm } 394b2765275SChristian Gromm 395b2765275SChristian Gromm if (!list_empty(&mdev_link_list)) 396b2765275SChristian Gromm list_del(&mdev_link->list); 397b2765275SChristian Gromm 398b2765275SChristian Gromm free_item: 399b2765275SChristian Gromm kfree(to_mdev_link(item)); 400b2765275SChristian Gromm } 401b2765275SChristian Gromm 402b2765275SChristian Gromm static struct configfs_item_operations mdev_link_item_ops = { 403b2765275SChristian Gromm .release = mdev_link_release, 404b2765275SChristian Gromm }; 405b2765275SChristian Gromm 406b2765275SChristian Gromm static const struct config_item_type mdev_link_type = { 407b2765275SChristian Gromm .ct_item_ops = &mdev_link_item_ops, 408b2765275SChristian Gromm .ct_attrs = mdev_link_attrs, 409b2765275SChristian Gromm .ct_owner = THIS_MODULE, 410b2765275SChristian Gromm }; 411b2765275SChristian Gromm 412b2765275SChristian Gromm struct most_common { 413b2765275SChristian Gromm struct config_group group; 414b2765275SChristian Gromm struct module *mod; 415b2765275SChristian Gromm struct configfs_subsystem subsys; 416b2765275SChristian Gromm }; 417b2765275SChristian Gromm 418b2765275SChristian Gromm static struct most_common *to_most_common(struct configfs_subsystem *subsys) 419b2765275SChristian Gromm { 420b2765275SChristian Gromm return container_of(subsys, struct most_common, subsys); 421b2765275SChristian Gromm } 422b2765275SChristian Gromm 423b2765275SChristian Gromm static struct config_item *most_common_make_item(struct config_group *group, 424b2765275SChristian Gromm const char *name) 425b2765275SChristian Gromm { 426b2765275SChristian Gromm struct mdev_link *mdev_link; 427b2765275SChristian Gromm struct most_common *mc = to_most_common(group->cg_subsys); 428b2765275SChristian Gromm 429b2765275SChristian Gromm mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 430b2765275SChristian Gromm if (!mdev_link) 431b2765275SChristian Gromm return ERR_PTR(-ENOMEM); 432b2765275SChristian Gromm 433b2765275SChristian Gromm if (!try_module_get(mc->mod)) { 434b2765275SChristian Gromm kfree(mdev_link); 435b2765275SChristian Gromm return ERR_PTR(-ENOLCK); 436b2765275SChristian Gromm } 437b2765275SChristian Gromm config_item_init_type_name(&mdev_link->item, name, 438b2765275SChristian Gromm &mdev_link_type); 439b2765275SChristian Gromm 440b2765275SChristian Gromm if (!strcmp(group->cg_item.ci_namebuf, "most_cdev")) 441b2765275SChristian Gromm strcpy(mdev_link->comp, "cdev"); 442b2765275SChristian Gromm else if (!strcmp(group->cg_item.ci_namebuf, "most_net")) 443b2765275SChristian Gromm strcpy(mdev_link->comp, "net"); 444b2765275SChristian Gromm else if (!strcmp(group->cg_item.ci_namebuf, "most_video")) 445b2765275SChristian Gromm strcpy(mdev_link->comp, "video"); 446b2765275SChristian Gromm strcpy(mdev_link->name, name); 447b2765275SChristian Gromm return &mdev_link->item; 448b2765275SChristian Gromm } 449b2765275SChristian Gromm 450b2765275SChristian Gromm static void most_common_release(struct config_item *item) 451b2765275SChristian Gromm { 452b2765275SChristian Gromm struct config_group *group = to_config_group(item); 453b2765275SChristian Gromm 454b2765275SChristian Gromm kfree(to_most_common(group->cg_subsys)); 455b2765275SChristian Gromm } 456b2765275SChristian Gromm 457b2765275SChristian Gromm static struct configfs_item_operations most_common_item_ops = { 458b2765275SChristian Gromm .release = most_common_release, 459b2765275SChristian Gromm }; 460b2765275SChristian Gromm 461b2765275SChristian Gromm static void most_common_disconnect(struct config_group *group, 462b2765275SChristian Gromm struct config_item *item) 463b2765275SChristian Gromm { 464b2765275SChristian Gromm struct most_common *mc = to_most_common(group->cg_subsys); 465b2765275SChristian Gromm 466b2765275SChristian Gromm module_put(mc->mod); 467b2765275SChristian Gromm } 468b2765275SChristian Gromm 469b2765275SChristian Gromm static struct configfs_group_operations most_common_group_ops = { 470b2765275SChristian Gromm .make_item = most_common_make_item, 471b2765275SChristian Gromm .disconnect_notify = most_common_disconnect, 472b2765275SChristian Gromm }; 473b2765275SChristian Gromm 474b2765275SChristian Gromm static const struct config_item_type most_common_type = { 475b2765275SChristian Gromm .ct_item_ops = &most_common_item_ops, 476b2765275SChristian Gromm .ct_group_ops = &most_common_group_ops, 477b2765275SChristian Gromm .ct_owner = THIS_MODULE, 478b2765275SChristian Gromm }; 479b2765275SChristian Gromm 480b2765275SChristian Gromm static struct most_common most_cdev = { 481b2765275SChristian Gromm .subsys = { 482b2765275SChristian Gromm .su_group = { 483b2765275SChristian Gromm .cg_item = { 484b2765275SChristian Gromm .ci_namebuf = "most_cdev", 485b2765275SChristian Gromm .ci_type = &most_common_type, 486b2765275SChristian Gromm }, 487b2765275SChristian Gromm }, 488b2765275SChristian Gromm }, 489b2765275SChristian Gromm }; 490b2765275SChristian Gromm 491b2765275SChristian Gromm static struct most_common most_net = { 492b2765275SChristian Gromm .subsys = { 493b2765275SChristian Gromm .su_group = { 494b2765275SChristian Gromm .cg_item = { 495b2765275SChristian Gromm .ci_namebuf = "most_net", 496b2765275SChristian Gromm .ci_type = &most_common_type, 497b2765275SChristian Gromm }, 498b2765275SChristian Gromm }, 499b2765275SChristian Gromm }, 500b2765275SChristian Gromm }; 501b2765275SChristian Gromm 502b2765275SChristian Gromm static struct most_common most_video = { 503b2765275SChristian Gromm .subsys = { 504b2765275SChristian Gromm .su_group = { 505b2765275SChristian Gromm .cg_item = { 506b2765275SChristian Gromm .ci_namebuf = "most_video", 507b2765275SChristian Gromm .ci_type = &most_common_type, 508b2765275SChristian Gromm }, 509b2765275SChristian Gromm }, 510b2765275SChristian Gromm }, 511b2765275SChristian Gromm }; 512b2765275SChristian Gromm 513b2765275SChristian Gromm struct most_snd_grp { 514b2765275SChristian Gromm struct config_group group; 515b2765275SChristian Gromm bool create_card; 516b2765275SChristian Gromm struct list_head list; 517b2765275SChristian Gromm }; 518b2765275SChristian Gromm 519b2765275SChristian Gromm static struct most_snd_grp *to_most_snd_grp(struct config_item *item) 520b2765275SChristian Gromm { 521b2765275SChristian Gromm return container_of(to_config_group(item), struct most_snd_grp, group); 522b2765275SChristian Gromm } 523b2765275SChristian Gromm 524b2765275SChristian Gromm static struct config_item *most_snd_grp_make_item(struct config_group *group, 525b2765275SChristian Gromm const char *name) 526b2765275SChristian Gromm { 527b2765275SChristian Gromm struct mdev_link *mdev_link; 528b2765275SChristian Gromm 529b2765275SChristian Gromm mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 530b2765275SChristian Gromm if (!mdev_link) 531b2765275SChristian Gromm return ERR_PTR(-ENOMEM); 532b2765275SChristian Gromm 533b2765275SChristian Gromm config_item_init_type_name(&mdev_link->item, name, &mdev_link_type); 534b2765275SChristian Gromm mdev_link->create_link = false; 535b2765275SChristian Gromm strcpy(mdev_link->name, name); 536b2765275SChristian Gromm strcpy(mdev_link->comp, "sound"); 537b2765275SChristian Gromm return &mdev_link->item; 538b2765275SChristian Gromm } 539b2765275SChristian Gromm 540b2765275SChristian Gromm static ssize_t most_snd_grp_create_card_store(struct config_item *item, 541b2765275SChristian Gromm const char *page, size_t count) 542b2765275SChristian Gromm { 543b2765275SChristian Gromm struct most_snd_grp *snd_grp = to_most_snd_grp(item); 544b2765275SChristian Gromm int ret; 545b2765275SChristian Gromm bool tmp; 546b2765275SChristian Gromm 547b2765275SChristian Gromm ret = kstrtobool(page, &tmp); 548b2765275SChristian Gromm if (ret) 549b2765275SChristian Gromm return ret; 550b2765275SChristian Gromm if (tmp) { 551b2765275SChristian Gromm ret = most_cfg_complete("sound"); 552b2765275SChristian Gromm if (ret) 553b2765275SChristian Gromm return ret; 554b2765275SChristian Gromm } 555b2765275SChristian Gromm snd_grp->create_card = tmp; 556b2765275SChristian Gromm return count; 557b2765275SChristian Gromm } 558b2765275SChristian Gromm 559b2765275SChristian Gromm CONFIGFS_ATTR_WO(most_snd_grp_, create_card); 560b2765275SChristian Gromm 561b2765275SChristian Gromm static struct configfs_attribute *most_snd_grp_attrs[] = { 562b2765275SChristian Gromm &most_snd_grp_attr_create_card, 563b2765275SChristian Gromm NULL, 564b2765275SChristian Gromm }; 565b2765275SChristian Gromm 566b2765275SChristian Gromm static void most_snd_grp_release(struct config_item *item) 567b2765275SChristian Gromm { 568b2765275SChristian Gromm struct most_snd_grp *group = to_most_snd_grp(item); 569b2765275SChristian Gromm 570b2765275SChristian Gromm list_del(&group->list); 571b2765275SChristian Gromm kfree(group); 572b2765275SChristian Gromm } 573b2765275SChristian Gromm 574b2765275SChristian Gromm static struct configfs_item_operations most_snd_grp_item_ops = { 575b2765275SChristian Gromm .release = most_snd_grp_release, 576b2765275SChristian Gromm }; 577b2765275SChristian Gromm 578b2765275SChristian Gromm static struct configfs_group_operations most_snd_grp_group_ops = { 579b2765275SChristian Gromm .make_item = most_snd_grp_make_item, 580b2765275SChristian Gromm }; 581b2765275SChristian Gromm 582b2765275SChristian Gromm static const struct config_item_type most_snd_grp_type = { 583b2765275SChristian Gromm .ct_item_ops = &most_snd_grp_item_ops, 584b2765275SChristian Gromm .ct_group_ops = &most_snd_grp_group_ops, 585b2765275SChristian Gromm .ct_attrs = most_snd_grp_attrs, 586b2765275SChristian Gromm .ct_owner = THIS_MODULE, 587b2765275SChristian Gromm }; 588b2765275SChristian Gromm 589b2765275SChristian Gromm struct most_sound { 590b2765275SChristian Gromm struct configfs_subsystem subsys; 591b2765275SChristian Gromm struct list_head soundcard_list; 592b2765275SChristian Gromm struct module *mod; 593b2765275SChristian Gromm }; 594b2765275SChristian Gromm 595b2765275SChristian Gromm static struct config_group *most_sound_make_group(struct config_group *group, 596b2765275SChristian Gromm const char *name) 597b2765275SChristian Gromm { 598b2765275SChristian Gromm struct most_snd_grp *most; 599b2765275SChristian Gromm struct most_sound *ms = container_of(group->cg_subsys, 600b2765275SChristian Gromm struct most_sound, subsys); 601b2765275SChristian Gromm 602b2765275SChristian Gromm list_for_each_entry(most, &ms->soundcard_list, list) { 603b2765275SChristian Gromm if (!most->create_card) { 604b2765275SChristian Gromm pr_info("adapter configuration still in progress.\n"); 605b2765275SChristian Gromm return ERR_PTR(-EPROTO); 606b2765275SChristian Gromm } 607b2765275SChristian Gromm } 608b2765275SChristian Gromm if (!try_module_get(ms->mod)) 609b2765275SChristian Gromm return ERR_PTR(-ENOLCK); 610b2765275SChristian Gromm most = kzalloc(sizeof(*most), GFP_KERNEL); 611b2765275SChristian Gromm if (!most) { 612b2765275SChristian Gromm module_put(ms->mod); 613b2765275SChristian Gromm return ERR_PTR(-ENOMEM); 614b2765275SChristian Gromm } 615b2765275SChristian Gromm config_group_init_type_name(&most->group, name, &most_snd_grp_type); 616b2765275SChristian Gromm list_add_tail(&most->list, &ms->soundcard_list); 617b2765275SChristian Gromm return &most->group; 618b2765275SChristian Gromm } 619b2765275SChristian Gromm 620b2765275SChristian Gromm static void most_sound_disconnect(struct config_group *group, 621b2765275SChristian Gromm struct config_item *item) 622b2765275SChristian Gromm { 623b2765275SChristian Gromm struct most_sound *ms = container_of(group->cg_subsys, 624b2765275SChristian Gromm struct most_sound, subsys); 625b2765275SChristian Gromm module_put(ms->mod); 626b2765275SChristian Gromm } 627b2765275SChristian Gromm 628b2765275SChristian Gromm static struct configfs_group_operations most_sound_group_ops = { 629b2765275SChristian Gromm .make_group = most_sound_make_group, 630b2765275SChristian Gromm .disconnect_notify = most_sound_disconnect, 631b2765275SChristian Gromm }; 632b2765275SChristian Gromm 633b2765275SChristian Gromm static const struct config_item_type most_sound_type = { 634b2765275SChristian Gromm .ct_group_ops = &most_sound_group_ops, 635b2765275SChristian Gromm .ct_owner = THIS_MODULE, 636b2765275SChristian Gromm }; 637b2765275SChristian Gromm 638b2765275SChristian Gromm static struct most_sound most_sound_subsys = { 639b2765275SChristian Gromm .subsys = { 640b2765275SChristian Gromm .su_group = { 641b2765275SChristian Gromm .cg_item = { 642b2765275SChristian Gromm .ci_namebuf = "most_sound", 643b2765275SChristian Gromm .ci_type = &most_sound_type, 644b2765275SChristian Gromm }, 645b2765275SChristian Gromm }, 646b2765275SChristian Gromm }, 647b2765275SChristian Gromm }; 648b2765275SChristian Gromm 649b2765275SChristian Gromm int most_register_configfs_subsys(struct most_component *c) 650b2765275SChristian Gromm { 651b2765275SChristian Gromm int ret; 652b2765275SChristian Gromm 653b2765275SChristian Gromm if (!strcmp(c->name, "cdev")) { 654b2765275SChristian Gromm most_cdev.mod = c->mod; 655b2765275SChristian Gromm ret = configfs_register_subsystem(&most_cdev.subsys); 656b2765275SChristian Gromm } else if (!strcmp(c->name, "net")) { 657b2765275SChristian Gromm most_net.mod = c->mod; 658b2765275SChristian Gromm ret = configfs_register_subsystem(&most_net.subsys); 659b2765275SChristian Gromm } else if (!strcmp(c->name, "video")) { 660b2765275SChristian Gromm most_video.mod = c->mod; 661b2765275SChristian Gromm ret = configfs_register_subsystem(&most_video.subsys); 662b2765275SChristian Gromm } else if (!strcmp(c->name, "sound")) { 663b2765275SChristian Gromm most_sound_subsys.mod = c->mod; 664b2765275SChristian Gromm ret = configfs_register_subsystem(&most_sound_subsys.subsys); 665b2765275SChristian Gromm } else { 666b2765275SChristian Gromm return -ENODEV; 667b2765275SChristian Gromm } 668b2765275SChristian Gromm 669b2765275SChristian Gromm if (ret) { 670b2765275SChristian Gromm pr_err("Error %d while registering subsystem %s\n", 671b2765275SChristian Gromm ret, c->name); 672b2765275SChristian Gromm } 673b2765275SChristian Gromm return ret; 674b2765275SChristian Gromm } 675b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_register_configfs_subsys); 676b2765275SChristian Gromm 677b2765275SChristian Gromm void most_interface_register_notify(const char *mdev) 678b2765275SChristian Gromm { 679b2765275SChristian Gromm bool register_snd_card = false; 680b2765275SChristian Gromm struct mdev_link *mdev_link; 681b2765275SChristian Gromm 682b2765275SChristian Gromm list_for_each_entry(mdev_link, &mdev_link_list, list) { 683b2765275SChristian Gromm if (!strcmp(mdev_link->device, mdev)) { 684b2765275SChristian Gromm set_config_and_add_link(mdev_link); 685b2765275SChristian Gromm if (!strcmp(mdev_link->comp, "sound")) 686b2765275SChristian Gromm register_snd_card = true; 687b2765275SChristian Gromm } 688b2765275SChristian Gromm } 689b2765275SChristian Gromm if (register_snd_card) 690b2765275SChristian Gromm most_cfg_complete("sound"); 691b2765275SChristian Gromm } 692b2765275SChristian Gromm 693b2765275SChristian Gromm void most_deregister_configfs_subsys(struct most_component *c) 694b2765275SChristian Gromm { 695b2765275SChristian Gromm if (!strcmp(c->name, "cdev")) 696b2765275SChristian Gromm configfs_unregister_subsystem(&most_cdev.subsys); 697b2765275SChristian Gromm else if (!strcmp(c->name, "net")) 698b2765275SChristian Gromm configfs_unregister_subsystem(&most_net.subsys); 699b2765275SChristian Gromm else if (!strcmp(c->name, "video")) 700b2765275SChristian Gromm configfs_unregister_subsystem(&most_video.subsys); 701b2765275SChristian Gromm else if (!strcmp(c->name, "sound")) 702b2765275SChristian Gromm configfs_unregister_subsystem(&most_sound_subsys.subsys); 703b2765275SChristian Gromm } 704b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys); 705b2765275SChristian Gromm 706b2765275SChristian Gromm int __init configfs_init(void) 707b2765275SChristian Gromm { 708b2765275SChristian Gromm config_group_init(&most_cdev.subsys.su_group); 709b2765275SChristian Gromm mutex_init(&most_cdev.subsys.su_mutex); 710b2765275SChristian Gromm 711b2765275SChristian Gromm config_group_init(&most_net.subsys.su_group); 712b2765275SChristian Gromm mutex_init(&most_net.subsys.su_mutex); 713b2765275SChristian Gromm 714b2765275SChristian Gromm config_group_init(&most_video.subsys.su_group); 715b2765275SChristian Gromm mutex_init(&most_video.subsys.su_mutex); 716b2765275SChristian Gromm 717b2765275SChristian Gromm config_group_init(&most_sound_subsys.subsys.su_group); 718b2765275SChristian Gromm mutex_init(&most_sound_subsys.subsys.su_mutex); 719b2765275SChristian Gromm 720b2765275SChristian Gromm INIT_LIST_HEAD(&most_sound_subsys.soundcard_list); 721b2765275SChristian Gromm INIT_LIST_HEAD(&mdev_link_list); 722b2765275SChristian Gromm 723b2765275SChristian Gromm return 0; 724b2765275SChristian Gromm } 725