162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * configfs.c - Implementation of configfs interface to the driver stack 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/configfs.h> 1362306a36Sopenharmony_ci#include <linux/most.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define MAX_STRING_SIZE 80 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct mdev_link { 1862306a36Sopenharmony_ci struct config_item item; 1962306a36Sopenharmony_ci struct list_head list; 2062306a36Sopenharmony_ci bool create_link; 2162306a36Sopenharmony_ci bool destroy_link; 2262306a36Sopenharmony_ci u16 num_buffers; 2362306a36Sopenharmony_ci u16 buffer_size; 2462306a36Sopenharmony_ci u16 subbuffer_size; 2562306a36Sopenharmony_ci u16 packets_per_xact; 2662306a36Sopenharmony_ci u16 dbr_size; 2762306a36Sopenharmony_ci char datatype[MAX_STRING_SIZE]; 2862306a36Sopenharmony_ci char direction[MAX_STRING_SIZE]; 2962306a36Sopenharmony_ci char name[MAX_STRING_SIZE]; 3062306a36Sopenharmony_ci char device[MAX_STRING_SIZE]; 3162306a36Sopenharmony_ci char channel[MAX_STRING_SIZE]; 3262306a36Sopenharmony_ci char comp[MAX_STRING_SIZE]; 3362306a36Sopenharmony_ci char comp_params[MAX_STRING_SIZE]; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct list_head mdev_link_list; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int set_cfg_buffer_size(struct mdev_link *link) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci return most_set_cfg_buffer_size(link->device, link->channel, 4162306a36Sopenharmony_ci link->buffer_size); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int set_cfg_subbuffer_size(struct mdev_link *link) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return most_set_cfg_subbuffer_size(link->device, link->channel, 4762306a36Sopenharmony_ci link->subbuffer_size); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int set_cfg_dbr_size(struct mdev_link *link) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return most_set_cfg_dbr_size(link->device, link->channel, 5362306a36Sopenharmony_ci link->dbr_size); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int set_cfg_num_buffers(struct mdev_link *link) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci return most_set_cfg_num_buffers(link->device, link->channel, 5962306a36Sopenharmony_ci link->num_buffers); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int set_cfg_packets_xact(struct mdev_link *link) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci return most_set_cfg_packets_xact(link->device, link->channel, 6562306a36Sopenharmony_ci link->packets_per_xact); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int set_cfg_direction(struct mdev_link *link) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci return most_set_cfg_direction(link->device, link->channel, 7162306a36Sopenharmony_ci link->direction); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int set_cfg_datatype(struct mdev_link *link) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return most_set_cfg_datatype(link->device, link->channel, 7762306a36Sopenharmony_ci link->datatype); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int (*set_config_val[])(struct mdev_link *link) = { 8162306a36Sopenharmony_ci set_cfg_buffer_size, 8262306a36Sopenharmony_ci set_cfg_subbuffer_size, 8362306a36Sopenharmony_ci set_cfg_dbr_size, 8462306a36Sopenharmony_ci set_cfg_num_buffers, 8562306a36Sopenharmony_ci set_cfg_packets_xact, 8662306a36Sopenharmony_ci set_cfg_direction, 8762306a36Sopenharmony_ci set_cfg_datatype, 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct mdev_link *to_mdev_link(struct config_item *item) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci return container_of(item, struct mdev_link, item); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int set_config_and_add_link(struct mdev_link *mdev_link) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int i; 9862306a36Sopenharmony_ci int ret; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(set_config_val); i++) { 10162306a36Sopenharmony_ci ret = set_config_val[i](mdev_link); 10262306a36Sopenharmony_ci if (ret < 0 && ret != -ENODEV) { 10362306a36Sopenharmony_ci pr_err("Config failed\n"); 10462306a36Sopenharmony_ci return ret; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return most_add_link(mdev_link->device, mdev_link->channel, 10962306a36Sopenharmony_ci mdev_link->comp, mdev_link->name, 11062306a36Sopenharmony_ci mdev_link->comp_params); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic ssize_t mdev_link_create_link_store(struct config_item *item, 11462306a36Sopenharmony_ci const char *page, size_t count) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 11762306a36Sopenharmony_ci bool tmp; 11862306a36Sopenharmony_ci int ret; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ret = kstrtobool(page, &tmp); 12162306a36Sopenharmony_ci if (ret) 12262306a36Sopenharmony_ci return ret; 12362306a36Sopenharmony_ci if (!tmp) 12462306a36Sopenharmony_ci return count; 12562306a36Sopenharmony_ci ret = set_config_and_add_link(mdev_link); 12662306a36Sopenharmony_ci if (ret && ret != -ENODEV) 12762306a36Sopenharmony_ci return ret; 12862306a36Sopenharmony_ci list_add_tail(&mdev_link->list, &mdev_link_list); 12962306a36Sopenharmony_ci mdev_link->create_link = tmp; 13062306a36Sopenharmony_ci mdev_link->destroy_link = false; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return count; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic ssize_t mdev_link_destroy_link_store(struct config_item *item, 13662306a36Sopenharmony_ci const char *page, size_t count) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 13962306a36Sopenharmony_ci bool tmp; 14062306a36Sopenharmony_ci int ret; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci ret = kstrtobool(page, &tmp); 14362306a36Sopenharmony_ci if (ret) 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci if (!tmp) 14662306a36Sopenharmony_ci return count; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = most_remove_link(mdev_link->device, mdev_link->channel, 14962306a36Sopenharmony_ci mdev_link->comp); 15062306a36Sopenharmony_ci if (ret) 15162306a36Sopenharmony_ci return ret; 15262306a36Sopenharmony_ci if (!list_empty(&mdev_link_list)) 15362306a36Sopenharmony_ci list_del(&mdev_link->list); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci mdev_link->destroy_link = tmp; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return count; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic ssize_t mdev_link_direction_show(struct config_item *item, char *page) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->direction); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic ssize_t mdev_link_direction_store(struct config_item *item, 16662306a36Sopenharmony_ci const char *page, size_t count) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!sysfs_streq(page, "dir_rx") && !sysfs_streq(page, "rx") && 17162306a36Sopenharmony_ci !sysfs_streq(page, "dir_tx") && !sysfs_streq(page, "tx")) 17262306a36Sopenharmony_ci return -EINVAL; 17362306a36Sopenharmony_ci strcpy(mdev_link->direction, page); 17462306a36Sopenharmony_ci strim(mdev_link->direction); 17562306a36Sopenharmony_ci return count; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic ssize_t mdev_link_datatype_show(struct config_item *item, char *page) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->datatype); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic ssize_t mdev_link_datatype_store(struct config_item *item, 18462306a36Sopenharmony_ci const char *page, size_t count) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (!sysfs_streq(page, "control") && !sysfs_streq(page, "async") && 18962306a36Sopenharmony_ci !sysfs_streq(page, "sync") && !sysfs_streq(page, "isoc") && 19062306a36Sopenharmony_ci !sysfs_streq(page, "isoc_avp")) 19162306a36Sopenharmony_ci return -EINVAL; 19262306a36Sopenharmony_ci strcpy(mdev_link->datatype, page); 19362306a36Sopenharmony_ci strim(mdev_link->datatype); 19462306a36Sopenharmony_ci return count; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic ssize_t mdev_link_device_show(struct config_item *item, char *page) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->device); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic ssize_t mdev_link_device_store(struct config_item *item, 20362306a36Sopenharmony_ci const char *page, size_t count) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci strscpy(mdev_link->device, page, sizeof(mdev_link->device)); 20862306a36Sopenharmony_ci strim(mdev_link->device); 20962306a36Sopenharmony_ci return count; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic ssize_t mdev_link_channel_show(struct config_item *item, char *page) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->channel); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic ssize_t mdev_link_channel_store(struct config_item *item, 21862306a36Sopenharmony_ci const char *page, size_t count) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci strscpy(mdev_link->channel, page, sizeof(mdev_link->channel)); 22362306a36Sopenharmony_ci strim(mdev_link->channel); 22462306a36Sopenharmony_ci return count; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic ssize_t mdev_link_comp_show(struct config_item *item, char *page) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->comp); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic ssize_t mdev_link_comp_store(struct config_item *item, 23362306a36Sopenharmony_ci const char *page, size_t count) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci strscpy(mdev_link->comp, page, sizeof(mdev_link->comp)); 23862306a36Sopenharmony_ci strim(mdev_link->comp); 23962306a36Sopenharmony_ci return count; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic ssize_t mdev_link_comp_params_show(struct config_item *item, char *page) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%s\n", 24562306a36Sopenharmony_ci to_mdev_link(item)->comp_params); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic ssize_t mdev_link_comp_params_store(struct config_item *item, 24962306a36Sopenharmony_ci const char *page, size_t count) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci strscpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); 25462306a36Sopenharmony_ci strim(mdev_link->comp_params); 25562306a36Sopenharmony_ci return count; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic ssize_t mdev_link_num_buffers_show(struct config_item *item, char *page) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%d\n", 26162306a36Sopenharmony_ci to_mdev_link(item)->num_buffers); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic ssize_t mdev_link_num_buffers_store(struct config_item *item, 26562306a36Sopenharmony_ci const char *page, size_t count) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 26862306a36Sopenharmony_ci int ret; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ret = kstrtou16(page, 0, &mdev_link->num_buffers); 27162306a36Sopenharmony_ci if (ret) 27262306a36Sopenharmony_ci return ret; 27362306a36Sopenharmony_ci return count; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic ssize_t mdev_link_buffer_size_show(struct config_item *item, char *page) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%d\n", 27962306a36Sopenharmony_ci to_mdev_link(item)->buffer_size); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic ssize_t mdev_link_buffer_size_store(struct config_item *item, 28362306a36Sopenharmony_ci const char *page, size_t count) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = kstrtou16(page, 0, &mdev_link->buffer_size); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci return count; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic ssize_t mdev_link_subbuffer_size_show(struct config_item *item, 29562306a36Sopenharmony_ci char *page) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%d\n", 29862306a36Sopenharmony_ci to_mdev_link(item)->subbuffer_size); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic ssize_t mdev_link_subbuffer_size_store(struct config_item *item, 30262306a36Sopenharmony_ci const char *page, size_t count) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 30562306a36Sopenharmony_ci int ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci ret = kstrtou16(page, 0, &mdev_link->subbuffer_size); 30862306a36Sopenharmony_ci if (ret) 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci return count; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic ssize_t mdev_link_packets_per_xact_show(struct config_item *item, 31462306a36Sopenharmony_ci char *page) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%d\n", 31762306a36Sopenharmony_ci to_mdev_link(item)->packets_per_xact); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic ssize_t mdev_link_packets_per_xact_store(struct config_item *item, 32162306a36Sopenharmony_ci const char *page, size_t count) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 32462306a36Sopenharmony_ci int ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ret = kstrtou16(page, 0, &mdev_link->packets_per_xact); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci return ret; 32962306a36Sopenharmony_ci return count; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic ssize_t mdev_link_dbr_size_show(struct config_item *item, char *page) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci return snprintf(page, PAGE_SIZE, "%d\n", to_mdev_link(item)->dbr_size); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic ssize_t mdev_link_dbr_size_store(struct config_item *item, 33862306a36Sopenharmony_ci const char *page, size_t count) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 34162306a36Sopenharmony_ci int ret; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = kstrtou16(page, 0, &mdev_link->dbr_size); 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci return ret; 34662306a36Sopenharmony_ci return count; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ciCONFIGFS_ATTR_WO(mdev_link_, create_link); 35062306a36Sopenharmony_ciCONFIGFS_ATTR_WO(mdev_link_, destroy_link); 35162306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, device); 35262306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, channel); 35362306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, comp); 35462306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, comp_params); 35562306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, num_buffers); 35662306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, buffer_size); 35762306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, subbuffer_size); 35862306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, packets_per_xact); 35962306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, datatype); 36062306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, direction); 36162306a36Sopenharmony_ciCONFIGFS_ATTR(mdev_link_, dbr_size); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic struct configfs_attribute *mdev_link_attrs[] = { 36462306a36Sopenharmony_ci &mdev_link_attr_create_link, 36562306a36Sopenharmony_ci &mdev_link_attr_destroy_link, 36662306a36Sopenharmony_ci &mdev_link_attr_device, 36762306a36Sopenharmony_ci &mdev_link_attr_channel, 36862306a36Sopenharmony_ci &mdev_link_attr_comp, 36962306a36Sopenharmony_ci &mdev_link_attr_comp_params, 37062306a36Sopenharmony_ci &mdev_link_attr_num_buffers, 37162306a36Sopenharmony_ci &mdev_link_attr_buffer_size, 37262306a36Sopenharmony_ci &mdev_link_attr_subbuffer_size, 37362306a36Sopenharmony_ci &mdev_link_attr_packets_per_xact, 37462306a36Sopenharmony_ci &mdev_link_attr_datatype, 37562306a36Sopenharmony_ci &mdev_link_attr_direction, 37662306a36Sopenharmony_ci &mdev_link_attr_dbr_size, 37762306a36Sopenharmony_ci NULL, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void mdev_link_release(struct config_item *item) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct mdev_link *mdev_link = to_mdev_link(item); 38362306a36Sopenharmony_ci int ret; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (mdev_link->destroy_link) 38662306a36Sopenharmony_ci goto free_item; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ret = most_remove_link(mdev_link->device, mdev_link->channel, 38962306a36Sopenharmony_ci mdev_link->comp); 39062306a36Sopenharmony_ci if (ret) { 39162306a36Sopenharmony_ci pr_err("Removing link failed.\n"); 39262306a36Sopenharmony_ci goto free_item; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!list_empty(&mdev_link_list)) 39662306a36Sopenharmony_ci list_del(&mdev_link->list); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cifree_item: 39962306a36Sopenharmony_ci kfree(to_mdev_link(item)); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic struct configfs_item_operations mdev_link_item_ops = { 40362306a36Sopenharmony_ci .release = mdev_link_release, 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic const struct config_item_type mdev_link_type = { 40762306a36Sopenharmony_ci .ct_item_ops = &mdev_link_item_ops, 40862306a36Sopenharmony_ci .ct_attrs = mdev_link_attrs, 40962306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistruct most_common { 41362306a36Sopenharmony_ci struct config_group group; 41462306a36Sopenharmony_ci struct module *mod; 41562306a36Sopenharmony_ci struct configfs_subsystem subsys; 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic struct most_common *to_most_common(struct configfs_subsystem *subsys) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci return container_of(subsys, struct most_common, subsys); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic struct config_item *most_common_make_item(struct config_group *group, 42462306a36Sopenharmony_ci const char *name) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct mdev_link *mdev_link; 42762306a36Sopenharmony_ci struct most_common *mc = to_most_common(group->cg_subsys); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 43062306a36Sopenharmony_ci if (!mdev_link) 43162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (!try_module_get(mc->mod)) { 43462306a36Sopenharmony_ci kfree(mdev_link); 43562306a36Sopenharmony_ci return ERR_PTR(-ENOLCK); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci config_item_init_type_name(&mdev_link->item, name, 43862306a36Sopenharmony_ci &mdev_link_type); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!strcmp(group->cg_item.ci_namebuf, "most_cdev")) 44162306a36Sopenharmony_ci strcpy(mdev_link->comp, "cdev"); 44262306a36Sopenharmony_ci else if (!strcmp(group->cg_item.ci_namebuf, "most_net")) 44362306a36Sopenharmony_ci strcpy(mdev_link->comp, "net"); 44462306a36Sopenharmony_ci else if (!strcmp(group->cg_item.ci_namebuf, "most_video")) 44562306a36Sopenharmony_ci strcpy(mdev_link->comp, "video"); 44662306a36Sopenharmony_ci strcpy(mdev_link->name, name); 44762306a36Sopenharmony_ci return &mdev_link->item; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void most_common_release(struct config_item *item) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct config_group *group = to_config_group(item); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci kfree(to_most_common(group->cg_subsys)); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic struct configfs_item_operations most_common_item_ops = { 45862306a36Sopenharmony_ci .release = most_common_release, 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void most_common_disconnect(struct config_group *group, 46262306a36Sopenharmony_ci struct config_item *item) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct most_common *mc = to_most_common(group->cg_subsys); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci module_put(mc->mod); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic struct configfs_group_operations most_common_group_ops = { 47062306a36Sopenharmony_ci .make_item = most_common_make_item, 47162306a36Sopenharmony_ci .disconnect_notify = most_common_disconnect, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic const struct config_item_type most_common_type = { 47562306a36Sopenharmony_ci .ct_item_ops = &most_common_item_ops, 47662306a36Sopenharmony_ci .ct_group_ops = &most_common_group_ops, 47762306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 47862306a36Sopenharmony_ci}; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic struct most_common most_cdev = { 48162306a36Sopenharmony_ci .subsys = { 48262306a36Sopenharmony_ci .su_group = { 48362306a36Sopenharmony_ci .cg_item = { 48462306a36Sopenharmony_ci .ci_namebuf = "most_cdev", 48562306a36Sopenharmony_ci .ci_type = &most_common_type, 48662306a36Sopenharmony_ci }, 48762306a36Sopenharmony_ci }, 48862306a36Sopenharmony_ci }, 48962306a36Sopenharmony_ci}; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic struct most_common most_net = { 49262306a36Sopenharmony_ci .subsys = { 49362306a36Sopenharmony_ci .su_group = { 49462306a36Sopenharmony_ci .cg_item = { 49562306a36Sopenharmony_ci .ci_namebuf = "most_net", 49662306a36Sopenharmony_ci .ci_type = &most_common_type, 49762306a36Sopenharmony_ci }, 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci }, 50062306a36Sopenharmony_ci}; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic struct most_common most_video = { 50362306a36Sopenharmony_ci .subsys = { 50462306a36Sopenharmony_ci .su_group = { 50562306a36Sopenharmony_ci .cg_item = { 50662306a36Sopenharmony_ci .ci_namebuf = "most_video", 50762306a36Sopenharmony_ci .ci_type = &most_common_type, 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci }, 51062306a36Sopenharmony_ci }, 51162306a36Sopenharmony_ci}; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistruct most_snd_grp { 51462306a36Sopenharmony_ci struct config_group group; 51562306a36Sopenharmony_ci bool create_card; 51662306a36Sopenharmony_ci struct list_head list; 51762306a36Sopenharmony_ci}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic struct most_snd_grp *to_most_snd_grp(struct config_item *item) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci return container_of(to_config_group(item), struct most_snd_grp, group); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic struct config_item *most_snd_grp_make_item(struct config_group *group, 52562306a36Sopenharmony_ci const char *name) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct mdev_link *mdev_link; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 53062306a36Sopenharmony_ci if (!mdev_link) 53162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci config_item_init_type_name(&mdev_link->item, name, &mdev_link_type); 53462306a36Sopenharmony_ci mdev_link->create_link = false; 53562306a36Sopenharmony_ci strcpy(mdev_link->name, name); 53662306a36Sopenharmony_ci strcpy(mdev_link->comp, "sound"); 53762306a36Sopenharmony_ci return &mdev_link->item; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic ssize_t most_snd_grp_create_card_store(struct config_item *item, 54162306a36Sopenharmony_ci const char *page, size_t count) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct most_snd_grp *snd_grp = to_most_snd_grp(item); 54462306a36Sopenharmony_ci int ret; 54562306a36Sopenharmony_ci bool tmp; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = kstrtobool(page, &tmp); 54862306a36Sopenharmony_ci if (ret) 54962306a36Sopenharmony_ci return ret; 55062306a36Sopenharmony_ci if (tmp) { 55162306a36Sopenharmony_ci ret = most_cfg_complete("sound"); 55262306a36Sopenharmony_ci if (ret) 55362306a36Sopenharmony_ci return ret; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci snd_grp->create_card = tmp; 55662306a36Sopenharmony_ci return count; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ciCONFIGFS_ATTR_WO(most_snd_grp_, create_card); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic struct configfs_attribute *most_snd_grp_attrs[] = { 56262306a36Sopenharmony_ci &most_snd_grp_attr_create_card, 56362306a36Sopenharmony_ci NULL, 56462306a36Sopenharmony_ci}; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void most_snd_grp_release(struct config_item *item) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct most_snd_grp *group = to_most_snd_grp(item); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci list_del(&group->list); 57162306a36Sopenharmony_ci kfree(group); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic struct configfs_item_operations most_snd_grp_item_ops = { 57562306a36Sopenharmony_ci .release = most_snd_grp_release, 57662306a36Sopenharmony_ci}; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic struct configfs_group_operations most_snd_grp_group_ops = { 57962306a36Sopenharmony_ci .make_item = most_snd_grp_make_item, 58062306a36Sopenharmony_ci}; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic const struct config_item_type most_snd_grp_type = { 58362306a36Sopenharmony_ci .ct_item_ops = &most_snd_grp_item_ops, 58462306a36Sopenharmony_ci .ct_group_ops = &most_snd_grp_group_ops, 58562306a36Sopenharmony_ci .ct_attrs = most_snd_grp_attrs, 58662306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 58762306a36Sopenharmony_ci}; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistruct most_sound { 59062306a36Sopenharmony_ci struct configfs_subsystem subsys; 59162306a36Sopenharmony_ci struct list_head soundcard_list; 59262306a36Sopenharmony_ci struct module *mod; 59362306a36Sopenharmony_ci}; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic struct config_group *most_sound_make_group(struct config_group *group, 59662306a36Sopenharmony_ci const char *name) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct most_snd_grp *most; 59962306a36Sopenharmony_ci struct most_sound *ms = container_of(group->cg_subsys, 60062306a36Sopenharmony_ci struct most_sound, subsys); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci list_for_each_entry(most, &ms->soundcard_list, list) { 60362306a36Sopenharmony_ci if (!most->create_card) { 60462306a36Sopenharmony_ci pr_info("adapter configuration still in progress.\n"); 60562306a36Sopenharmony_ci return ERR_PTR(-EPROTO); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci if (!try_module_get(ms->mod)) 60962306a36Sopenharmony_ci return ERR_PTR(-ENOLCK); 61062306a36Sopenharmony_ci most = kzalloc(sizeof(*most), GFP_KERNEL); 61162306a36Sopenharmony_ci if (!most) { 61262306a36Sopenharmony_ci module_put(ms->mod); 61362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci config_group_init_type_name(&most->group, name, &most_snd_grp_type); 61662306a36Sopenharmony_ci list_add_tail(&most->list, &ms->soundcard_list); 61762306a36Sopenharmony_ci return &most->group; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic void most_sound_disconnect(struct config_group *group, 62162306a36Sopenharmony_ci struct config_item *item) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct most_sound *ms = container_of(group->cg_subsys, 62462306a36Sopenharmony_ci struct most_sound, subsys); 62562306a36Sopenharmony_ci module_put(ms->mod); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic struct configfs_group_operations most_sound_group_ops = { 62962306a36Sopenharmony_ci .make_group = most_sound_make_group, 63062306a36Sopenharmony_ci .disconnect_notify = most_sound_disconnect, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic const struct config_item_type most_sound_type = { 63462306a36Sopenharmony_ci .ct_group_ops = &most_sound_group_ops, 63562306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 63662306a36Sopenharmony_ci}; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic struct most_sound most_sound_subsys = { 63962306a36Sopenharmony_ci .subsys = { 64062306a36Sopenharmony_ci .su_group = { 64162306a36Sopenharmony_ci .cg_item = { 64262306a36Sopenharmony_ci .ci_namebuf = "most_sound", 64362306a36Sopenharmony_ci .ci_type = &most_sound_type, 64462306a36Sopenharmony_ci }, 64562306a36Sopenharmony_ci }, 64662306a36Sopenharmony_ci }, 64762306a36Sopenharmony_ci}; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ciint most_register_configfs_subsys(struct most_component *c) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (!strcmp(c->name, "cdev")) { 65462306a36Sopenharmony_ci most_cdev.mod = c->mod; 65562306a36Sopenharmony_ci ret = configfs_register_subsystem(&most_cdev.subsys); 65662306a36Sopenharmony_ci } else if (!strcmp(c->name, "net")) { 65762306a36Sopenharmony_ci most_net.mod = c->mod; 65862306a36Sopenharmony_ci ret = configfs_register_subsystem(&most_net.subsys); 65962306a36Sopenharmony_ci } else if (!strcmp(c->name, "video")) { 66062306a36Sopenharmony_ci most_video.mod = c->mod; 66162306a36Sopenharmony_ci ret = configfs_register_subsystem(&most_video.subsys); 66262306a36Sopenharmony_ci } else if (!strcmp(c->name, "sound")) { 66362306a36Sopenharmony_ci most_sound_subsys.mod = c->mod; 66462306a36Sopenharmony_ci ret = configfs_register_subsystem(&most_sound_subsys.subsys); 66562306a36Sopenharmony_ci } else { 66662306a36Sopenharmony_ci return -ENODEV; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (ret) { 67062306a36Sopenharmony_ci pr_err("Error %d while registering subsystem %s\n", 67162306a36Sopenharmony_ci ret, c->name); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci return ret; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(most_register_configfs_subsys); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_civoid most_interface_register_notify(const char *mdev) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci bool register_snd_card = false; 68062306a36Sopenharmony_ci struct mdev_link *mdev_link; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci list_for_each_entry(mdev_link, &mdev_link_list, list) { 68362306a36Sopenharmony_ci if (!strcmp(mdev_link->device, mdev)) { 68462306a36Sopenharmony_ci set_config_and_add_link(mdev_link); 68562306a36Sopenharmony_ci if (!strcmp(mdev_link->comp, "sound")) 68662306a36Sopenharmony_ci register_snd_card = true; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci if (register_snd_card) 69062306a36Sopenharmony_ci most_cfg_complete("sound"); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_civoid most_deregister_configfs_subsys(struct most_component *c) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci if (!strcmp(c->name, "cdev")) 69662306a36Sopenharmony_ci configfs_unregister_subsystem(&most_cdev.subsys); 69762306a36Sopenharmony_ci else if (!strcmp(c->name, "net")) 69862306a36Sopenharmony_ci configfs_unregister_subsystem(&most_net.subsys); 69962306a36Sopenharmony_ci else if (!strcmp(c->name, "video")) 70062306a36Sopenharmony_ci configfs_unregister_subsystem(&most_video.subsys); 70162306a36Sopenharmony_ci else if (!strcmp(c->name, "sound")) 70262306a36Sopenharmony_ci configfs_unregister_subsystem(&most_sound_subsys.subsys); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(most_deregister_configfs_subsys); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciint __init configfs_init(void) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci config_group_init(&most_cdev.subsys.su_group); 70962306a36Sopenharmony_ci mutex_init(&most_cdev.subsys.su_mutex); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci config_group_init(&most_net.subsys.su_group); 71262306a36Sopenharmony_ci mutex_init(&most_net.subsys.su_mutex); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci config_group_init(&most_video.subsys.su_group); 71562306a36Sopenharmony_ci mutex_init(&most_video.subsys.su_mutex); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci config_group_init(&most_sound_subsys.subsys.su_group); 71862306a36Sopenharmony_ci mutex_init(&most_sound_subsys.subsys.su_mutex); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci INIT_LIST_HEAD(&most_sound_subsys.soundcard_list); 72162306a36Sopenharmony_ci INIT_LIST_HEAD(&mdev_link_list); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 725