Commit | Line | Data |
---|---|---|
b15d97d7 JH |
1 | /* |
2 | * Greybus Module code | |
3 | * | |
4 | * Copyright 2016 Google Inc. | |
5 | * Copyright 2016 Linaro Ltd. | |
6 | * | |
7 | * Released under the GPLv2 only. | |
8 | */ | |
9 | ||
10 | #include "greybus.h" | |
5451ea0e | 11 | #include "greybus_trace.h" |
b15d97d7 | 12 | |
dacf3eb7 | 13 | |
36602a29 JH |
14 | static ssize_t eject_store(struct device *dev, |
15 | struct device_attribute *attr, | |
16 | const char *buf, size_t len) | |
17 | { | |
18 | struct gb_module *module = to_gb_module(dev); | |
19 | struct gb_interface *intf; | |
20 | size_t i; | |
21 | long val; | |
22 | int ret; | |
23 | ||
24 | ret = kstrtol(buf, 0, &val); | |
25 | if (ret) | |
26 | return ret; | |
27 | ||
28 | if (!val) | |
29 | return len; | |
30 | ||
31 | for (i = 0; i < module->num_interfaces; ++i) { | |
32 | intf = module->interfaces[i]; | |
33 | ||
34 | mutex_lock(&intf->mutex); | |
35 | /* Set flag to prevent concurrent activation. */ | |
36 | intf->ejected = true; | |
37 | gb_interface_disable(intf); | |
38 | gb_interface_deactivate(intf); | |
39 | mutex_unlock(&intf->mutex); | |
40 | } | |
41 | ||
42 | /* Tell the SVC to eject the primary interface. */ | |
43 | ret = gb_svc_intf_eject(module->hd->svc, module->module_id); | |
44 | if (ret) | |
45 | return ret; | |
46 | ||
47 | return len; | |
48 | } | |
49 | static DEVICE_ATTR_WO(eject); | |
50 | ||
b15d97d7 JH |
51 | static ssize_t module_id_show(struct device *dev, |
52 | struct device_attribute *attr, char *buf) | |
53 | { | |
54 | struct gb_module *module = to_gb_module(dev); | |
55 | ||
56 | return sprintf(buf, "%u\n", module->module_id); | |
57 | } | |
58 | static DEVICE_ATTR_RO(module_id); | |
59 | ||
60 | static ssize_t num_interfaces_show(struct device *dev, | |
61 | struct device_attribute *attr, char *buf) | |
62 | { | |
63 | struct gb_module *module = to_gb_module(dev); | |
64 | ||
65 | return sprintf(buf, "%zu\n", module->num_interfaces); | |
66 | } | |
67 | static DEVICE_ATTR_RO(num_interfaces); | |
68 | ||
69 | static struct attribute *module_attrs[] = { | |
36602a29 | 70 | &dev_attr_eject.attr, |
b15d97d7 JH |
71 | &dev_attr_module_id.attr, |
72 | &dev_attr_num_interfaces.attr, | |
73 | NULL, | |
74 | }; | |
75 | ATTRIBUTE_GROUPS(module); | |
76 | ||
77 | static void gb_module_release(struct device *dev) | |
78 | { | |
79 | struct gb_module *module = to_gb_module(dev); | |
80 | ||
5451ea0e AE |
81 | trace_gb_module_release(module); |
82 | ||
b15d97d7 JH |
83 | kfree(module); |
84 | } | |
85 | ||
86 | struct device_type greybus_module_type = { | |
87 | .name = "greybus_module", | |
88 | .release = gb_module_release, | |
89 | }; | |
90 | ||
91 | struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id, | |
92 | size_t num_interfaces) | |
93 | { | |
94 | struct gb_interface *intf; | |
95 | struct gb_module *module; | |
96 | int i; | |
97 | ||
98 | module = kzalloc(sizeof(*module) + num_interfaces * sizeof(intf), | |
99 | GFP_KERNEL); | |
100 | if (!module) | |
101 | return NULL; | |
102 | ||
103 | module->hd = hd; | |
104 | module->module_id = module_id; | |
105 | module->num_interfaces = num_interfaces; | |
106 | ||
107 | module->dev.parent = &hd->dev; | |
108 | module->dev.bus = &greybus_bus_type; | |
109 | module->dev.type = &greybus_module_type; | |
110 | module->dev.groups = module_groups; | |
111 | module->dev.dma_mask = hd->dev.dma_mask; | |
112 | device_initialize(&module->dev); | |
113 | dev_set_name(&module->dev, "%d-%u", hd->bus_id, module_id); | |
114 | ||
5451ea0e AE |
115 | trace_gb_module_create(module); |
116 | ||
b15d97d7 JH |
117 | for (i = 0; i < num_interfaces; ++i) { |
118 | intf = gb_interface_create(module, module_id + i); | |
119 | if (!intf) { | |
120 | dev_err(&module->dev, "failed to create interface %u\n", | |
121 | module_id + i); | |
122 | goto err_put_interfaces; | |
123 | } | |
124 | module->interfaces[i] = intf; | |
125 | } | |
126 | ||
127 | return module; | |
128 | ||
129 | err_put_interfaces: | |
e866dd8a | 130 | for (--i; i >= 0; --i) |
b15d97d7 JH |
131 | gb_interface_put(module->interfaces[i]); |
132 | ||
133 | put_device(&module->dev); | |
134 | ||
135 | return NULL; | |
136 | } | |
137 | ||
138 | /* | |
139 | * Register and enable an interface after first attempting to activate it. | |
140 | */ | |
141 | static void gb_module_register_interface(struct gb_interface *intf) | |
142 | { | |
143 | struct gb_module *module = intf->module; | |
144 | u8 intf_id = intf->interface_id; | |
145 | int ret; | |
146 | ||
36602a29 JH |
147 | mutex_lock(&intf->mutex); |
148 | ||
3e93cb6a | 149 | ret = gb_interface_activate(intf); |
b15d97d7 | 150 | if (ret) { |
a212b758 | 151 | if (intf->type != GB_INTERFACE_TYPE_DUMMY) { |
6633d80a JH |
152 | dev_err(&module->dev, |
153 | "failed to activate interface %u: %d\n", | |
154 | intf_id, ret); | |
155 | } | |
e16715c1 | 156 | |
b15d97d7 | 157 | gb_interface_add(intf); |
36602a29 | 158 | goto err_unlock; |
b15d97d7 JH |
159 | } |
160 | ||
161 | ret = gb_interface_add(intf); | |
162 | if (ret) | |
163 | goto err_interface_deactivate; | |
164 | ||
165 | ret = gb_interface_enable(intf); | |
166 | if (ret) { | |
167 | dev_err(&module->dev, "failed to enable interface %u: %d\n", | |
168 | intf_id, ret); | |
169 | goto err_interface_deactivate; | |
170 | } | |
171 | ||
36602a29 JH |
172 | mutex_unlock(&intf->mutex); |
173 | ||
b15d97d7 JH |
174 | return; |
175 | ||
176 | err_interface_deactivate: | |
177 | gb_interface_deactivate(intf); | |
36602a29 JH |
178 | err_unlock: |
179 | mutex_unlock(&intf->mutex); | |
b15d97d7 JH |
180 | } |
181 | ||
182 | static void gb_module_deregister_interface(struct gb_interface *intf) | |
183 | { | |
184 | /* Mark as disconnected to prevent I/O during disable. */ | |
185 | if (intf->module->disconnected) | |
186 | intf->disconnected = true; | |
187 | ||
36602a29 | 188 | mutex_lock(&intf->mutex); |
12169bc9 | 189 | intf->removed = true; |
b15d97d7 JH |
190 | gb_interface_disable(intf); |
191 | gb_interface_deactivate(intf); | |
36602a29 | 192 | mutex_unlock(&intf->mutex); |
b15d97d7 JH |
193 | |
194 | gb_interface_del(intf); | |
195 | } | |
196 | ||
197 | /* Register a module and its interfaces. */ | |
198 | int gb_module_add(struct gb_module *module) | |
199 | { | |
200 | size_t i; | |
201 | int ret; | |
202 | ||
203 | ret = device_add(&module->dev); | |
204 | if (ret) { | |
205 | dev_err(&module->dev, "failed to register module: %d\n", ret); | |
206 | return ret; | |
207 | } | |
208 | ||
5451ea0e AE |
209 | trace_gb_module_add(module); |
210 | ||
b15d97d7 JH |
211 | for (i = 0; i < module->num_interfaces; ++i) |
212 | gb_module_register_interface(module->interfaces[i]); | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
217 | /* Deregister a module and its interfaces. */ | |
218 | void gb_module_del(struct gb_module *module) | |
219 | { | |
220 | size_t i; | |
221 | ||
222 | for (i = 0; i < module->num_interfaces; ++i) | |
223 | gb_module_deregister_interface(module->interfaces[i]); | |
224 | ||
5451ea0e AE |
225 | trace_gb_module_del(module); |
226 | ||
b15d97d7 JH |
227 | device_del(&module->dev); |
228 | } | |
229 | ||
230 | void gb_module_put(struct gb_module *module) | |
231 | { | |
232 | size_t i; | |
233 | ||
234 | for (i = 0; i < module->num_interfaces; ++i) | |
235 | gb_interface_put(module->interfaces[i]); | |
236 | ||
237 | put_device(&module->dev); | |
238 | } |