// SPDX-License-Identifier: GPL-2.0 /* * AVIRT - ALSA Virtual Soundcard * * Copyright (c) 2010-2019 Fiberdyne Systems Pty Ltd * * configfs.c - AVIRT sysfs support */ #include #include "core.h" #define D_LOGNAME "sysfs" #define D_INFOK(fmt, args...) DINFO(D_LOGNAME, fmt, ##args) #define D_PRINTK(fmt, args...) DDEBUG(D_LOGNAME, fmt, ##args) #define D_ERRORK(fmt, args...) DERROR(D_LOGNAME, fmt, ##args) static struct kset *snd_avirt_audiopath_kset; static struct kobject *kobj; #define to_audiopath_obj(d) \ container_of(d, struct snd_avirt_audiopath_obj, kobj) #define to_audiopath_attr(a) \ container_of(a, struct snd_avirt_audiopath_attribute, attr) /** * struct snd_avirt_audiopath_attribute - access the attributes of Audio Path * @attr: attributes of an Audio Path * @show: pointer to the show function * @store: pointer to the store function */ struct snd_avirt_audiopath_attribute { struct attribute attr; ssize_t (*show)(struct snd_avirt_audiopath_obj *d, struct snd_avirt_audiopath_attribute *attr, char *buf); ssize_t (*store)(struct snd_avirt_audiopath_obj *d, struct snd_avirt_audiopath_attribute *attr, const char *buf, size_t count); }; /** * audiopath_attr_show - show function of an Audio Path * @kobj: pointer to kobject * @attr: pointer to attribute struct * @buf: buffer */ static ssize_t audiopath_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct snd_avirt_audiopath_attribute *audiopath_attr; struct snd_avirt_audiopath_obj *audiopath_obj; audiopath_attr = to_audiopath_attr(attr); audiopath_obj = to_audiopath_obj(kobj); if (!audiopath_attr->show) return -EIO; return audiopath_attr->show(audiopath_obj, audiopath_attr, buf); } /** * audiopath_attr_store - attribute store function of Audio Path object * @kobj: pointer to kobject * @attr: pointer to attribute struct * @buf: buffer * @len: length of buffer */ static ssize_t audiopath_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { struct snd_avirt_audiopath_attribute *audiopath_attr; struct snd_avirt_audiopath_obj *audiopath_obj; audiopath_attr = to_audiopath_attr(attr); audiopath_obj = to_audiopath_obj(kobj); if (!audiopath_attr->store) return -EIO; return audiopath_attr->store(audiopath_obj, audiopath_attr, buf, len); } static const struct sysfs_ops snd_avirt_audiopath_sysfs_ops = { .show = audiopath_attr_show, .store = audiopath_attr_store, }; /** * snd_avirt_audiopath_release - Audio Path release function * @kobj: pointer to Audio Paths's kobject */ static void snd_avirt_audiopath_release(struct kobject *kobj) { struct snd_avirt_audiopath_obj *audiopath_obj = to_audiopath_obj(kobj); kfree(audiopath_obj); } static ssize_t name_show(struct snd_avirt_audiopath_obj *audiopath_obj, struct snd_avirt_audiopath_attribute *attr, char *buf) { return sprintf(buf, "%s\n", audiopath_obj->path->name); } static ssize_t version_show(struct snd_avirt_audiopath_obj *audiopath_obj, struct snd_avirt_audiopath_attribute *attr, char *buf) { struct snd_avirt_audiopath *audiopath = audiopath_obj->path; return sprintf(buf, "%d.%d.%d\n", audiopath->version[0], audiopath->version[1], audiopath->version[2]); } static struct snd_avirt_audiopath_attribute snd_avirt_audiopath_attrs[] = { __ATTR_RO(name), __ATTR_RO(version), }; static struct attribute *snd_avirt_audiopath_def_attrs[] = { &snd_avirt_audiopath_attrs[0].attr, &snd_avirt_audiopath_attrs[1].attr, NULL, }; static struct kobj_type snd_avirt_audiopath_ktype = { .sysfs_ops = &snd_avirt_audiopath_sysfs_ops, .release = snd_avirt_audiopath_release, .default_attrs = snd_avirt_audiopath_def_attrs, }; struct snd_avirt_audiopath_obj *snd_avirt_audiopath_create_obj(const char *uid) { struct snd_avirt_audiopath_obj *snd_avirt_audiopath; int retval; snd_avirt_audiopath = kzalloc(sizeof(*snd_avirt_audiopath), GFP_KERNEL); if (!snd_avirt_audiopath) return NULL; snd_avirt_audiopath->kobj.kset = snd_avirt_audiopath_kset; retval = kobject_init_and_add(&snd_avirt_audiopath->kobj, &snd_avirt_audiopath_ktype, kobj, "%s", uid); if (retval) { kobject_put(&snd_avirt_audiopath->kobj); return NULL; } kobject_uevent(&snd_avirt_audiopath->kobj, KOBJ_ADD); return snd_avirt_audiopath; } void snd_avirt_audiopath_destroy_obj(struct snd_avirt_audiopath_obj *p) { kobject_put(&p->kobj); } int __init snd_avirt_sysfs_init(struct snd_avirt_core *core) { snd_avirt_audiopath_kset = kset_create_and_add("audiopaths", NULL, &core->dev->kobj); if (!snd_avirt_audiopath_kset) return -ENOMEM; return 0; } void __exit snd_avirt_sysfs_exit(struct snd_avirt_core *core) { kset_unregister(snd_avirt_audiopath_kset); }