xref: /linux/drivers/staging/greybus/audio_manager_module.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
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 
to_gb_audio_module(struct kobject * kobj)16 static 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 
21 struct 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 
gb_audio_module_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)31 static 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 
gb_audio_module_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t len)46 static 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 
62 static 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 
gb_audio_module_release(struct kobject * kobj)67 static 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 	kfree(module);
73 }
74 
gb_audio_module_name_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)75 static ssize_t gb_audio_module_name_show(struct gb_audio_manager_module *module,
76 					 struct gb_audio_manager_module_attribute *attr, char *buf)
77 {
78 	return sysfs_emit(buf, "%s", module->desc.name);
79 }
80 
81 static struct gb_audio_manager_module_attribute gb_audio_module_name_attribute =
82 	__ATTR(name, 0664, gb_audio_module_name_show, NULL);
83 
gb_audio_module_vid_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)84 static ssize_t gb_audio_module_vid_show(struct gb_audio_manager_module *module,
85 					struct gb_audio_manager_module_attribute *attr, char *buf)
86 {
87 	return sysfs_emit(buf, "%d", module->desc.vid);
88 }
89 
90 static struct gb_audio_manager_module_attribute gb_audio_module_vid_attribute =
91 	__ATTR(vid, 0664, gb_audio_module_vid_show, NULL);
92 
gb_audio_module_pid_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)93 static ssize_t gb_audio_module_pid_show(struct gb_audio_manager_module *module,
94 					struct gb_audio_manager_module_attribute *attr, char *buf)
95 {
96 	return sysfs_emit(buf, "%d", module->desc.pid);
97 }
98 
99 static struct gb_audio_manager_module_attribute gb_audio_module_pid_attribute =
100 	__ATTR(pid, 0664, gb_audio_module_pid_show, NULL);
101 
gb_audio_module_intf_id_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)102 static ssize_t gb_audio_module_intf_id_show(struct gb_audio_manager_module *module,
103 					    struct gb_audio_manager_module_attribute *attr,
104 					    char *buf)
105 {
106 	return sysfs_emit(buf, "%d", module->desc.intf_id);
107 }
108 
109 static struct gb_audio_manager_module_attribute
110 					gb_audio_module_intf_id_attribute =
111 	__ATTR(intf_id, 0664, gb_audio_module_intf_id_show, NULL);
112 
gb_audio_module_ip_devices_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)113 static ssize_t gb_audio_module_ip_devices_show(struct gb_audio_manager_module *module,
114 					       struct gb_audio_manager_module_attribute *attr,
115 					       char *buf)
116 {
117 	return sysfs_emit(buf, "0x%X", module->desc.ip_devices);
118 }
119 
120 static struct gb_audio_manager_module_attribute
121 					gb_audio_module_ip_devices_attribute =
122 	__ATTR(ip_devices, 0664, gb_audio_module_ip_devices_show, NULL);
123 
gb_audio_module_op_devices_show(struct gb_audio_manager_module * module,struct gb_audio_manager_module_attribute * attr,char * buf)124 static ssize_t gb_audio_module_op_devices_show(struct gb_audio_manager_module *module,
125 					       struct gb_audio_manager_module_attribute *attr,
126 					       char *buf)
127 {
128 	return sysfs_emit(buf, "0x%X", module->desc.op_devices);
129 }
130 
131 static struct gb_audio_manager_module_attribute
132 					gb_audio_module_op_devices_attribute =
133 	__ATTR(op_devices, 0664, gb_audio_module_op_devices_show, NULL);
134 
135 static struct attribute *gb_audio_module_default_attrs[] = {
136 	&gb_audio_module_name_attribute.attr,
137 	&gb_audio_module_vid_attribute.attr,
138 	&gb_audio_module_pid_attribute.attr,
139 	&gb_audio_module_intf_id_attribute.attr,
140 	&gb_audio_module_ip_devices_attribute.attr,
141 	&gb_audio_module_op_devices_attribute.attr,
142 	NULL,   /* need to NULL terminate the list of attributes */
143 };
144 ATTRIBUTE_GROUPS(gb_audio_module_default);
145 
146 static const struct kobj_type gb_audio_module_type = {
147 	.sysfs_ops = &gb_audio_module_sysfs_ops,
148 	.release = gb_audio_module_release,
149 	.default_groups = gb_audio_module_default_groups,
150 };
151 
send_add_uevent(struct gb_audio_manager_module * module)152 static void send_add_uevent(struct gb_audio_manager_module *module)
153 {
154 	char name_string[128];
155 	char vid_string[64];
156 	char pid_string[64];
157 	char intf_id_string[64];
158 	char ip_devices_string[64];
159 	char op_devices_string[64];
160 
161 	char *envp[] = {
162 		name_string,
163 		vid_string,
164 		pid_string,
165 		intf_id_string,
166 		ip_devices_string,
167 		op_devices_string,
168 		NULL
169 	};
170 
171 	snprintf(name_string, 128, "NAME=%s", module->desc.name);
172 	snprintf(vid_string, 64, "VID=%d", module->desc.vid);
173 	snprintf(pid_string, 64, "PID=%d", module->desc.pid);
174 	snprintf(intf_id_string, 64, "INTF_ID=%d", module->desc.intf_id);
175 	snprintf(ip_devices_string, 64, "I/P DEVICES=0x%X",
176 		 module->desc.ip_devices);
177 	snprintf(op_devices_string, 64, "O/P DEVICES=0x%X",
178 		 module->desc.op_devices);
179 
180 	kobject_uevent_env(&module->kobj, KOBJ_ADD, envp);
181 }
182 
gb_audio_manager_module_create(struct gb_audio_manager_module ** module,struct kset * manager_kset,int id,struct gb_audio_manager_module_descriptor * desc)183 int gb_audio_manager_module_create(struct gb_audio_manager_module **module,
184 				   struct kset *manager_kset,
185 				   int id, struct gb_audio_manager_module_descriptor *desc)
186 {
187 	int err;
188 	struct gb_audio_manager_module *m;
189 
190 	m = kzalloc_obj(*m, GFP_ATOMIC);
191 	if (!m)
192 		return -ENOMEM;
193 
194 	/* Initialize the node */
195 	INIT_LIST_HEAD(&m->list);
196 
197 	/* Set the module id */
198 	m->id = id;
199 
200 	/* Copy the provided descriptor */
201 	memcpy(&m->desc, desc, sizeof(*desc));
202 
203 	/* set the kset */
204 	m->kobj.kset = manager_kset;
205 
206 	/*
207 	 * Initialize and add the kobject to the kernel.  All the default files
208 	 * will be created here.  As we have already specified a kset for this
209 	 * kobject, we don't have to set a parent for the kobject, the kobject
210 	 * will be placed beneath that kset automatically.
211 	 */
212 	err = kobject_init_and_add(&m->kobj, &gb_audio_module_type, NULL, "%d",
213 				   id);
214 	if (err) {
215 		pr_err("failed initializing kobject for audio module #%d\n", id);
216 		kobject_put(&m->kobj);
217 		return err;
218 	}
219 
220 	/*
221 	 * Notify the object was created
222 	 */
223 	send_add_uevent(m);
224 
225 	*module = m;
226 	pr_info("Created audio module #%d\n", id);
227 	return 0;
228 }
229 
gb_audio_manager_module_dump(struct gb_audio_manager_module * module)230 void gb_audio_manager_module_dump(struct gb_audio_manager_module *module)
231 {
232 	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",
233 		module->id,
234 		module->desc.name,
235 		module->desc.vid,
236 		module->desc.pid,
237 		module->desc.intf_id,
238 		module->desc.ip_devices,
239 		module->desc.op_devices);
240 }
241