1
2
3
4
5
6
7
8
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#define CREATE_TRACE_POINTS
13#include "greybus.h"
14#include "greybus_trace.h"
15
16#define GB_BUNDLE_AUTOSUSPEND_MS 3000
17
18
19static bool nogreybus;
20#ifdef MODULE
21module_param(nogreybus, bool, 0444);
22#else
23core_param(nogreybus, nogreybus, bool, 0444);
24#endif
25int greybus_disabled(void)
26{
27 return nogreybus;
28}
29EXPORT_SYMBOL_GPL(greybus_disabled);
30
31static bool greybus_match_one_id(struct gb_bundle *bundle,
32 const struct greybus_bundle_id *id)
33{
34 if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
35 (id->vendor != bundle->intf->vendor_id))
36 return false;
37
38 if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
39 (id->product != bundle->intf->product_id))
40 return false;
41
42 if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
43 (id->class != bundle->class))
44 return false;
45
46 return true;
47}
48
49static const struct greybus_bundle_id *
50greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
51{
52 if (id == NULL)
53 return NULL;
54
55 for (; id->vendor || id->product || id->class || id->driver_info;
56 id++) {
57 if (greybus_match_one_id(bundle, id))
58 return id;
59 }
60
61 return NULL;
62}
63
64static int greybus_match_device(struct device *dev, struct device_driver *drv)
65{
66 struct greybus_driver *driver = to_greybus_driver(drv);
67 struct gb_bundle *bundle;
68 const struct greybus_bundle_id *id;
69
70 if (!is_gb_bundle(dev))
71 return 0;
72
73 bundle = to_gb_bundle(dev);
74
75 id = greybus_match_id(bundle, driver->id_table);
76 if (id)
77 return 1;
78
79 return 0;
80}
81
82static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
83{
84 struct gb_host_device *hd;
85 struct gb_module *module = NULL;
86 struct gb_interface *intf = NULL;
87 struct gb_control *control = NULL;
88 struct gb_bundle *bundle = NULL;
89 struct gb_svc *svc = NULL;
90
91 if (is_gb_host_device(dev)) {
92 hd = to_gb_host_device(dev);
93 } else if (is_gb_module(dev)) {
94 module = to_gb_module(dev);
95 hd = module->hd;
96 } else if (is_gb_interface(dev)) {
97 intf = to_gb_interface(dev);
98 module = intf->module;
99 hd = intf->hd;
100 } else if (is_gb_control(dev)) {
101 control = to_gb_control(dev);
102 intf = control->intf;
103 module = intf->module;
104 hd = intf->hd;
105 } else if (is_gb_bundle(dev)) {
106 bundle = to_gb_bundle(dev);
107 intf = bundle->intf;
108 module = intf->module;
109 hd = intf->hd;
110 } else if (is_gb_svc(dev)) {
111 svc = to_gb_svc(dev);
112 hd = svc->hd;
113 } else {
114 dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
115 return -EINVAL;
116 }
117
118 if (add_uevent_var(env, "BUS=%u", hd->bus_id))
119 return -ENOMEM;
120
121 if (module) {
122 if (add_uevent_var(env, "MODULE=%u", module->module_id))
123 return -ENOMEM;
124 }
125
126 if (intf) {
127 if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
128 return -ENOMEM;
129 if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",
130 intf->vendor_id, intf->product_id))
131 return -ENOMEM;
132 }
133
134 if (bundle) {
135
136
137
138
139
140 if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
141 return -ENOMEM;
142 if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))
143 return -ENOMEM;
144 }
145
146 return 0;
147}
148
149static void greybus_shutdown(struct device *dev)
150{
151 if (is_gb_host_device(dev)) {
152 struct gb_host_device *hd;
153
154 hd = to_gb_host_device(dev);
155 gb_hd_shutdown(hd);
156 }
157}
158
159struct bus_type greybus_bus_type = {
160 .name = "greybus",
161 .match = greybus_match_device,
162 .uevent = greybus_uevent,
163 .shutdown = greybus_shutdown,
164};
165
166static int greybus_probe(struct device *dev)
167{
168 struct greybus_driver *driver = to_greybus_driver(dev->driver);
169 struct gb_bundle *bundle = to_gb_bundle(dev);
170 const struct greybus_bundle_id *id;
171 int retval;
172
173
174 id = greybus_match_id(bundle, driver->id_table);
175 if (!id)
176 return -ENODEV;
177
178 retval = pm_runtime_get_sync(&bundle->intf->dev);
179 if (retval < 0) {
180 pm_runtime_put_noidle(&bundle->intf->dev);
181 return retval;
182 }
183
184 retval = gb_control_bundle_activate(bundle->intf->control, bundle->id);
185 if (retval) {
186 pm_runtime_put(&bundle->intf->dev);
187 return retval;
188 }
189
190
191
192
193
194
195
196
197 pm_runtime_set_autosuspend_delay(dev, GB_BUNDLE_AUTOSUSPEND_MS);
198 pm_runtime_use_autosuspend(dev);
199 pm_runtime_get_noresume(dev);
200 pm_runtime_set_active(dev);
201 pm_runtime_enable(dev);
202
203 retval = driver->probe(bundle, id);
204 if (retval) {
205
206
207
208 WARN_ON(!list_empty(&bundle->connections));
209
210 gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
211
212 pm_runtime_disable(dev);
213 pm_runtime_set_suspended(dev);
214 pm_runtime_put_noidle(dev);
215 pm_runtime_dont_use_autosuspend(dev);
216 pm_runtime_put(&bundle->intf->dev);
217
218 return retval;
219 }
220
221 pm_runtime_put(&bundle->intf->dev);
222
223 return 0;
224}
225
226static int greybus_remove(struct device *dev)
227{
228 struct greybus_driver *driver = to_greybus_driver(dev->driver);
229 struct gb_bundle *bundle = to_gb_bundle(dev);
230 struct gb_connection *connection;
231 int retval;
232
233 retval = pm_runtime_get_sync(dev);
234 if (retval < 0)
235 dev_err(dev, "failed to resume bundle: %d\n", retval);
236
237
238
239
240
241
242 list_for_each_entry(connection, &bundle->connections, bundle_links) {
243 if (gb_connection_is_offloaded(connection))
244 continue;
245
246 if (bundle->intf->disconnected)
247 gb_connection_disable_forced(connection);
248 else
249 gb_connection_disable_rx(connection);
250 }
251
252 driver->disconnect(bundle);
253
254
255 WARN_ON(!list_empty(&bundle->connections));
256
257 if (!bundle->intf->disconnected)
258 gb_control_bundle_deactivate(bundle->intf->control, bundle->id);
259
260 pm_runtime_put_noidle(dev);
261 pm_runtime_disable(dev);
262 pm_runtime_set_suspended(dev);
263 pm_runtime_dont_use_autosuspend(dev);
264 pm_runtime_put_noidle(dev);
265
266 return 0;
267}
268
269int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
270 const char *mod_name)
271{
272 int retval;
273
274 if (greybus_disabled())
275 return -ENODEV;
276
277 driver->driver.bus = &greybus_bus_type;
278 driver->driver.name = driver->name;
279 driver->driver.probe = greybus_probe;
280 driver->driver.remove = greybus_remove;
281 driver->driver.owner = owner;
282 driver->driver.mod_name = mod_name;
283
284 retval = driver_register(&driver->driver);
285 if (retval)
286 return retval;
287
288 pr_info("registered new driver %s\n", driver->name);
289 return 0;
290}
291EXPORT_SYMBOL_GPL(greybus_register_driver);
292
293void greybus_deregister_driver(struct greybus_driver *driver)
294{
295 driver_unregister(&driver->driver);
296}
297EXPORT_SYMBOL_GPL(greybus_deregister_driver);
298
299static int __init gb_init(void)
300{
301 int retval;
302
303 if (greybus_disabled())
304 return -ENODEV;
305
306 BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
307
308 gb_debugfs_init();
309
310 retval = bus_register(&greybus_bus_type);
311 if (retval) {
312 pr_err("bus_register failed (%d)\n", retval);
313 goto error_bus;
314 }
315
316 retval = gb_hd_init();
317 if (retval) {
318 pr_err("gb_hd_init failed (%d)\n", retval);
319 goto error_hd;
320 }
321
322 retval = gb_operation_init();
323 if (retval) {
324 pr_err("gb_operation_init failed (%d)\n", retval);
325 goto error_operation;
326 }
327 return 0;
328
329error_operation:
330 gb_hd_exit();
331error_hd:
332 bus_unregister(&greybus_bus_type);
333error_bus:
334 gb_debugfs_cleanup();
335
336 return retval;
337}
338module_init(gb_init);
339
340static void __exit gb_exit(void)
341{
342 gb_operation_exit();
343 gb_hd_exit();
344 bus_unregister(&greybus_bus_type);
345 gb_debugfs_cleanup();
346 tracepoint_synchronize_unregister();
347}
348module_exit(gb_exit);
349MODULE_LICENSE("GPL v2");
350MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
351