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