1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Greybus operations
4 *
5 * Copyright 2015-2016 Google Inc.
6 */
7
8#include <linux/slab.h>
9
10#include "audio_manager.h"
11#include "audio_manager_private.h"
12
13#define to_gb_audio_module_attr(x)	\
14		container_of(x, struct gb_audio_manager_module_attribute, attr)
15
16static inline struct gb_audio_manager_module *to_gb_audio_module(struct kobject *kobj)
17{
18	return container_of(kobj, struct gb_audio_manager_module, kobj);
19}
20
21struct gb_audio_manager_module_attribute {
22	struct attribute attr;
23	ssize_t (*show)(struct gb_audio_manager_module *module,
24			struct gb_audio_manager_module_attribute *attr,
25			char *buf);
26	ssize_t (*store)(struct gb_audio_manager_module *module,
27			 struct gb_audio_manager_module_attribute *attr,
28			 const char *buf, size_t count);
29};
30
31static ssize_t gb_audio_module_attr_show(struct kobject *kobj,
32					 struct attribute *attr, char *buf)
33{
34	struct gb_audio_manager_module_attribute *attribute;
35	struct gb_audio_manager_module *module;
36
37	attribute = to_gb_audio_module_attr(attr);
38	module = to_gb_audio_module(kobj);
39
40	if (!attribute->show)
41		return -EIO;
42
43	return attribute->show(module, attribute, buf);
44}
45
46static ssize_t gb_audio_module_attr_store(struct kobject *kobj,
47					  struct attribute *attr,
48					  const char *buf, size_t len)
49{
50	struct gb_audio_manager_module_attribute *attribute;
51	struct gb_audio_manager_module *module;
52
53	attribute = to_gb_audio_module_attr(attr);
54	module = to_gb_audio_module(kobj);
55
56	if (!attribute->store)
57		return -EIO;
58
59	return attribute->store(module, attribute, buf, len);
60}
61
62static const struct sysfs_ops gb_audio_module_sysfs_ops = {
63	.show = gb_audio_module_attr_show,
64	.store = gb_audio_module_attr_store,
65};
66
67static void gb_audio_module_release(struct kobject *kobj)
68{
69	struct gb_audio_manager_module *module = to_gb_audio_module(kobj);
70
71	pr_info("Destroying audio module #%d\n", module->id);
72	/* TODO -> delete from list */
73	kfree(module);
74}
75
76static ssize_t gb_audio_module_name_show(struct gb_audio_manager_module *module,
77					 struct gb_audio_manager_module_attribute *attr, char *buf)
78{
79	return sprintf(buf, "%s", module->desc.name);
80}
81
82static struct gb_audio_manager_module_attribute gb_audio_module_name_attribute =
83	__ATTR(name, 0664, gb_audio_module_name_show, NULL);
84
85static ssize_t gb_audio_module_vid_show(struct gb_audio_manager_module *module,
86					struct gb_audio_manager_module_attribute *attr, char *buf)
87{
88	return sprintf(buf, "%d", module->desc.vid);
89}
90
91static struct gb_audio_manager_module_attribute gb_audio_module_vid_attribute =
92	__ATTR(vid, 0664, gb_audio_module_vid_show, NULL);
93
94static ssize_t gb_audio_module_pid_show(struct gb_audio_manager_module *module,
95					struct gb_audio_manager_module_attribute *attr, char *buf)
96{
97	return sprintf(buf, "%d", module->desc.pid);
98}
99
100static struct gb_audio_manager_module_attribute gb_audio_module_pid_attribute =
101	__ATTR(pid, 0664, gb_audio_module_pid_show, NULL);
102
103static ssize_t gb_audio_module_intf_id_show(struct gb_audio_manager_module *module,
104					    struct gb_audio_manager_module_attribute *attr,
105					    char *buf)
106{
107	return sprintf(buf, "%d", module->desc.intf_id);
108}
109
110static struct gb_audio_manager_module_attribute
111					gb_audio_module_intf_id_attribute =
112	__ATTR(intf_id, 0664, gb_audio_module_intf_id_show, NULL);
113
114static ssize_t gb_audio_module_ip_devices_show(struct gb_audio_manager_module *module,
115					       struct gb_audio_manager_module_attribute *attr,
116					       char *buf)
117{
118	return sprintf(buf, "0x%X", module->desc.ip_devices);
119}
120
121static struct gb_audio_manager_module_attribute
122					gb_audio_module_ip_devices_attribute =
123	__ATTR(ip_devices, 0664, gb_audio_module_ip_devices_show, NULL);
124
125static ssize_t gb_audio_module_op_devices_show(struct gb_audio_manager_module *module,
126					       struct gb_audio_manager_module_attribute *attr,
127					       char *buf)
128{
129	return sprintf(buf, "0x%X", module->desc.op_devices);
130}
131
132static struct gb_audio_manager_module_attribute
133					gb_audio_module_op_devices_attribute =
134	__ATTR(op_devices, 0664, gb_audio_module_op_devices_show, NULL);
135
136static struct attribute *gb_audio_module_default_attrs[] = {
137	&gb_audio_module_name_attribute.attr,
138	&gb_audio_module_vid_attribute.attr,
139	&gb_audio_module_pid_attribute.attr,
140	&gb_audio_module_intf_id_attribute.attr,
141	&gb_audio_module_ip_devices_attribute.attr,
142	&gb_audio_module_op_devices_attribute.attr,
143	NULL,   /* need to NULL terminate the list of attributes */
144};
145ATTRIBUTE_GROUPS(gb_audio_module_default);
146
147static struct kobj_type gb_audio_module_type = {
148	.sysfs_ops = &gb_audio_module_sysfs_ops,
149	.release = gb_audio_module_release,
150	.default_groups = gb_audio_module_default_groups,
151};
152
153static void send_add_uevent(struct gb_audio_manager_module *module)
154{
155	char name_string[128];
156	char vid_string[64];
157	char pid_string[64];
158	char intf_id_string[64];
159	char ip_devices_string[64];
160	char op_devices_string[64];
161
162	char *envp[] = {
163		name_string,
164		vid_string,
165		pid_string,
166		intf_id_string,
167		ip_devices_string,
168		op_devices_string,
169		NULL
170	};
171
172	snprintf(name_string, 128, "NAME=%s", module->desc.name);
173	snprintf(vid_string, 64, "VID=%d", module->desc.vid);
174	snprintf(pid_string, 64, "PID=%d", module->desc.pid);
175	snprintf(intf_id_string, 64, "INTF_ID=%d", module->desc.intf_id);
176	snprintf(ip_devices_string, 64, "I/P DEVICES=0x%X",
177		 module->desc.ip_devices);
178	snprintf(op_devices_string, 64, "O/P DEVICES=0x%X",
179		 module->desc.op_devices);
180
181	kobject_uevent_env(&module->kobj, KOBJ_ADD, envp);
182}
183
184int gb_audio_manager_module_create(struct gb_audio_manager_module **module,
185				   struct kset *manager_kset,
186				   int id, struct gb_audio_manager_module_descriptor *desc)
187{
188	int err;
189	struct gb_audio_manager_module *m;
190
191	m = kzalloc(sizeof(*m), GFP_ATOMIC);
192	if (!m)
193		return -ENOMEM;
194
195	/* Initialize the node */
196	INIT_LIST_HEAD(&m->list);
197
198	/* Set the module id */
199	m->id = id;
200
201	/* Copy the provided descriptor */
202	memcpy(&m->desc, desc, sizeof(*desc));
203
204	/* set the kset */
205	m->kobj.kset = manager_kset;
206
207	/*
208	 * Initialize and add the kobject to the kernel.  All the default files
209	 * will be created here.  As we have already specified a kset for this
210	 * kobject, we don't have to set a parent for the kobject, the kobject
211	 * will be placed beneath that kset automatically.
212	 */
213	err = kobject_init_and_add(&m->kobj, &gb_audio_module_type, NULL, "%d",
214				   id);
215	if (err) {
216		pr_err("failed initializing kobject for audio module #%d\n", id);
217		kobject_put(&m->kobj);
218		return err;
219	}
220
221	/*
222	 * Notify the object was created
223	 */
224	send_add_uevent(m);
225
226	*module = m;
227	pr_info("Created audio module #%d\n", id);
228	return 0;
229}
230
231void gb_audio_manager_module_dump(struct gb_audio_manager_module *module)
232{
233	pr_info("audio module #%d name=%s vid=%d pid=%d intf_id=%d i/p devices=0x%X o/p devices=0x%X\n",
234		module->id,
235		module->desc.name,
236		module->desc.vid,
237		module->desc.pid,
238		module->desc.intf_id,
239		module->desc.ip_devices,
240		module->desc.op_devices);
241}
242