|
@@ -0,0 +1,240 @@
|
|
|
+/*
|
|
|
+ * Greybus operations
|
|
|
+ *
|
|
|
+ * Copyright 2015-2016 Google Inc.
|
|
|
+ *
|
|
|
+ * Released under the GPLv2 only.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/slab.h>
|
|
|
+
|
|
|
+#include "audio_manager.h"
|
|
|
+#include "audio_manager_private.h"
|
|
|
+
|
|
|
+#define to_gb_audio_module_attr(x) \
|
|
|
+ container_of(x, struct gb_audio_manager_module_attribute, attr)
|
|
|
+#define to_gb_audio_module(x) \
|
|
|
+ container_of(x, struct gb_audio_manager_module, kobj)
|
|
|
+
|
|
|
+struct gb_audio_manager_module_attribute {
|
|
|
+ struct attribute attr;
|
|
|
+ ssize_t (*show)(struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr,
|
|
|
+ char *buf);
|
|
|
+ ssize_t (*store)(struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr,
|
|
|
+ const char *buf, size_t count);
|
|
|
+};
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_attr_show(
|
|
|
+ struct kobject *kobj, struct attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct gb_audio_manager_module_attribute *attribute;
|
|
|
+ struct gb_audio_manager_module *module;
|
|
|
+
|
|
|
+ attribute = to_gb_audio_module_attr(attr);
|
|
|
+ module = to_gb_audio_module(kobj);
|
|
|
+
|
|
|
+ if (!attribute->show)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return attribute->show(module, attribute, buf);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_attr_store(struct kobject *kobj,
|
|
|
+ struct attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ struct gb_audio_manager_module_attribute *attribute;
|
|
|
+ struct gb_audio_manager_module *module;
|
|
|
+
|
|
|
+ attribute = to_gb_audio_module_attr(attr);
|
|
|
+ module = to_gb_audio_module(kobj);
|
|
|
+
|
|
|
+ if (!attribute->store)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return attribute->store(module, attribute, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct sysfs_ops gb_audio_module_sysfs_ops = {
|
|
|
+ .show = gb_audio_module_attr_show,
|
|
|
+ .store = gb_audio_module_attr_store,
|
|
|
+};
|
|
|
+
|
|
|
+static void gb_audio_module_release(struct kobject *kobj)
|
|
|
+{
|
|
|
+ struct gb_audio_manager_module *module = to_gb_audio_module(kobj);
|
|
|
+
|
|
|
+ pr_info("Destroying audio module #%d\n", module->id);
|
|
|
+ /* TODO -> delete from list */
|
|
|
+ kfree(module);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_name_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%s", module->desc.name);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute gb_audio_module_name_attribute =
|
|
|
+ __ATTR(name, 0664, gb_audio_module_name_show, NULL);
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_slot_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d", module->desc.slot);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute gb_audio_module_slot_attribute =
|
|
|
+ __ATTR(slot, 0664, gb_audio_module_slot_show, NULL);
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_vid_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d", module->desc.vid);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute gb_audio_module_vid_attribute =
|
|
|
+ __ATTR(vid, 0664, gb_audio_module_vid_show, NULL);
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_pid_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d", module->desc.pid);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute gb_audio_module_pid_attribute =
|
|
|
+ __ATTR(pid, 0664, gb_audio_module_pid_show, NULL);
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_cport_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d", module->desc.cport);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute
|
|
|
+ gb_audio_module_cport_attribute =
|
|
|
+ __ATTR(cport, 0664, gb_audio_module_cport_show, NULL);
|
|
|
+
|
|
|
+static ssize_t gb_audio_module_devices_show(
|
|
|
+ struct gb_audio_manager_module *module,
|
|
|
+ struct gb_audio_manager_module_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "0x%X", module->desc.devices);
|
|
|
+}
|
|
|
+
|
|
|
+static struct gb_audio_manager_module_attribute
|
|
|
+ gb_audio_module_devices_attribute =
|
|
|
+ __ATTR(devices, 0664, gb_audio_module_devices_show, NULL);
|
|
|
+
|
|
|
+static struct attribute *gb_audio_module_default_attrs[] = {
|
|
|
+ &gb_audio_module_name_attribute.attr,
|
|
|
+ &gb_audio_module_slot_attribute.attr,
|
|
|
+ &gb_audio_module_vid_attribute.attr,
|
|
|
+ &gb_audio_module_pid_attribute.attr,
|
|
|
+ &gb_audio_module_cport_attribute.attr,
|
|
|
+ &gb_audio_module_devices_attribute.attr,
|
|
|
+ NULL, /* need to NULL terminate the list of attributes */
|
|
|
+};
|
|
|
+
|
|
|
+static struct kobj_type gb_audio_module_type = {
|
|
|
+ .sysfs_ops = &gb_audio_module_sysfs_ops,
|
|
|
+ .release = gb_audio_module_release,
|
|
|
+ .default_attrs = gb_audio_module_default_attrs,
|
|
|
+};
|
|
|
+
|
|
|
+static void send_add_uevent(struct gb_audio_manager_module *module)
|
|
|
+{
|
|
|
+ char name_string[128];
|
|
|
+ char slot_string[64];
|
|
|
+ char vid_string[64];
|
|
|
+ char pid_string[64];
|
|
|
+ char cport_string[64];
|
|
|
+ char devices_string[64];
|
|
|
+
|
|
|
+ char *envp[] = {
|
|
|
+ name_string,
|
|
|
+ slot_string,
|
|
|
+ vid_string,
|
|
|
+ pid_string,
|
|
|
+ cport_string,
|
|
|
+ devices_string,
|
|
|
+ NULL
|
|
|
+ };
|
|
|
+
|
|
|
+ snprintf(name_string, 128, "NAME=%s", module->desc.name);
|
|
|
+ snprintf(slot_string, 64, "SLOT=%d", module->desc.slot);
|
|
|
+ snprintf(vid_string, 64, "VID=%d", module->desc.vid);
|
|
|
+ snprintf(pid_string, 64, "PID=%d", module->desc.pid);
|
|
|
+ snprintf(cport_string, 64, "CPORT=%d", module->desc.cport);
|
|
|
+ snprintf(devices_string, 64, "DEVICES=0x%X", module->desc.devices);
|
|
|
+
|
|
|
+ kobject_uevent_env(&module->kobj, KOBJ_ADD, envp);
|
|
|
+}
|
|
|
+
|
|
|
+int gb_audio_manager_module_create(
|
|
|
+ struct gb_audio_manager_module **module,
|
|
|
+ struct kset *manager_kset,
|
|
|
+ int id, struct gb_audio_manager_module_descriptor *desc)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct gb_audio_manager_module *m;
|
|
|
+
|
|
|
+ m = kzalloc(sizeof(*m), GFP_ATOMIC);
|
|
|
+ if (!m)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /* Initialize the node */
|
|
|
+ INIT_LIST_HEAD(&m->list);
|
|
|
+
|
|
|
+ /* Set the module id */
|
|
|
+ m->id = id;
|
|
|
+
|
|
|
+ /* Copy the provided descriptor */
|
|
|
+ memcpy(&m->desc, desc, sizeof(*desc));
|
|
|
+
|
|
|
+ /* set the kset */
|
|
|
+ m->kobj.kset = manager_kset;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Initialize and add the kobject to the kernel. All the default files
|
|
|
+ * will be created here. As we have already specified a kset for this
|
|
|
+ * kobject, we don't have to set a parent for the kobject, the kobject
|
|
|
+ * will be placed beneath that kset automatically.
|
|
|
+ */
|
|
|
+ err = kobject_init_and_add(&m->kobj, &gb_audio_module_type, NULL, "%d",
|
|
|
+ id);
|
|
|
+ if (err) {
|
|
|
+ pr_err("failed initializing kobject for audio module #%d\n",
|
|
|
+ id);
|
|
|
+ kobject_put(&m->kobj);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Notify the object was created
|
|
|
+ */
|
|
|
+ send_add_uevent(m);
|
|
|
+
|
|
|
+ *module = m;
|
|
|
+ pr_info("Created audio module #%d\n", id);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void gb_audio_manager_module_dump(struct gb_audio_manager_module *module)
|
|
|
+{
|
|
|
+ pr_info("audio module #%d name=%s slot=%d vid=%d pid=%d cport=%d devices=0x%X\n",
|
|
|
+ module->id,
|
|
|
+ module->desc.name,
|
|
|
+ module->desc.slot,
|
|
|
+ module->desc.vid,
|
|
|
+ module->desc.pid,
|
|
|
+ module->desc.cport,
|
|
|
+ module->desc.devices);
|
|
|
+}
|