greybus: Revert "greybus: reserve host cport id 0"
[cascardo/linux.git] / drivers / staging / greybus / core.c
1 /*
2  * Greybus "Core"
3  *
4  * Copyright 2014-2015 Google Inc.
5  * Copyright 2014-2015 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12 #include "greybus.h"
13
14 /* Allow greybus to be disabled at boot if needed */
15 static bool nogreybus;
16 #ifdef MODULE
17 module_param(nogreybus, bool, 0444);
18 #else
19 core_param(nogreybus, nogreybus, bool, 0444);
20 #endif
21 int greybus_disabled(void)
22 {
23         return nogreybus;
24 }
25 EXPORT_SYMBOL_GPL(greybus_disabled);
26
27 static int greybus_module_match(struct device *dev, struct device_driver *drv)
28 {
29         struct greybus_driver *driver = to_greybus_driver(drv);
30         struct gb_bundle *bundle = to_gb_bundle(dev);
31         const struct greybus_bundle_id *id;
32
33         id = gb_bundle_match_id(bundle, driver->id_table);
34         if (id)
35                 return 1;
36         /* FIXME - Dynamic ids? */
37         return 0;
38 }
39
40 static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
41 {
42         struct gb_module *module = NULL;
43         struct gb_interface *intf = NULL;
44         struct gb_bundle *bundle = NULL;
45         struct gb_connection *connection = NULL;
46
47         if (is_gb_endo(dev)) {
48                 /*
49                  * Not much to do for an endo, just fall through, as the
50                  * "default" attributes are good enough for us.
51                  */
52                 return 0;
53         }
54
55         if (is_gb_module(dev)) {
56                 module = to_gb_module(dev);
57         } else if (is_gb_interface(dev)) {
58                 intf = to_gb_interface(dev);
59         } else if (is_gb_bundle(dev)) {
60                 bundle = to_gb_bundle(dev);
61                 intf = bundle->intf;
62         } else if (is_gb_connection(dev)) {
63                 connection = to_gb_connection(dev);
64                 bundle = connection->bundle;
65                 intf = bundle->intf;
66         } else {
67                 dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
68                 return -EINVAL;
69         }
70
71         if (connection) {
72                 // FIXME
73                 // add a uevent that can "load" a connection type
74                 return 0;
75         }
76
77         if (bundle) {
78                 // FIXME
79                 // add a uevent that can "load" a bundle type
80                 // This is what we need to bind a driver to so use the info
81                 // in gmod here as well
82                 return 0;
83         }
84
85         // FIXME
86         // "just" a module, be vague here, nothing binds to a module except
87         // the greybus core, so there's not much, if anything, we need to
88         // advertise.
89         return 0;
90 }
91
92 struct bus_type greybus_bus_type = {
93         .name =         "greybus",
94         .match =        greybus_module_match,
95         .uevent =       greybus_uevent,
96 };
97
98 static int greybus_probe(struct device *dev)
99 {
100         struct greybus_driver *driver = to_greybus_driver(dev->driver);
101         struct gb_bundle *bundle = to_gb_bundle(dev);
102         const struct greybus_bundle_id *id;
103         int retval;
104
105         /* match id */
106         id = gb_bundle_match_id(bundle, driver->id_table);
107         if (!id)
108                 return -ENODEV;
109
110         retval = driver->probe(bundle, id);
111         if (retval)
112                 return retval;
113
114         return 0;
115 }
116
117 static int greybus_remove(struct device *dev)
118 {
119         struct greybus_driver *driver = to_greybus_driver(dev->driver);
120         struct gb_bundle *bundle = to_gb_bundle(dev);
121
122         driver->disconnect(bundle);
123         return 0;
124 }
125
126 int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
127                 const char *mod_name)
128 {
129         int retval;
130
131         if (greybus_disabled())
132                 return -ENODEV;
133
134         driver->driver.name = driver->name;
135         driver->driver.probe = greybus_probe;
136         driver->driver.remove = greybus_remove;
137         driver->driver.owner = owner;
138         driver->driver.mod_name = mod_name;
139
140         retval = driver_register(&driver->driver);
141         if (retval)
142                 return retval;
143
144         pr_info("registered new driver %s\n", driver->name);
145         return 0;
146 }
147 EXPORT_SYMBOL_GPL(greybus_register_driver);
148
149 void greybus_deregister_driver(struct greybus_driver *driver)
150 {
151         driver_unregister(&driver->driver);
152 }
153 EXPORT_SYMBOL_GPL(greybus_deregister_driver);
154
155
156 static DEFINE_MUTEX(hd_mutex);
157
158 static void free_hd(struct kref *kref)
159 {
160         struct greybus_host_device *hd;
161
162         hd = container_of(kref, struct greybus_host_device, kref);
163
164         kfree(hd);
165         mutex_unlock(&hd_mutex);
166 }
167
168 struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
169                                               struct device *parent,
170                                               size_t buffer_size_max)
171 {
172         struct greybus_host_device *hd;
173
174         /*
175          * Validate that the driver implements all of the callbacks
176          * so that we don't have to every time we make them.
177          */
178         if ((!driver->message_send) || (!driver->message_cancel) ||
179             (!driver->submit_svc)) {
180                 pr_err("Must implement all greybus_host_driver callbacks!\n");
181                 return ERR_PTR(-EINVAL);
182         }
183
184         if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
185                 dev_err(parent, "greybus host-device buffers too small\n");
186                 return NULL;
187         }
188
189         /*
190          * Make sure to never allocate messages larger than what the Greybus
191          * protocol supports.
192          */
193         if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
194                 dev_warn(parent, "limiting buffer size to %u\n",
195                          GB_OPERATION_MESSAGE_SIZE_MAX);
196                 buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
197         }
198
199         hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
200         if (!hd)
201                 return ERR_PTR(-ENOMEM);
202
203         kref_init(&hd->kref);
204         hd->parent = parent;
205         hd->driver = driver;
206         INIT_LIST_HEAD(&hd->interfaces);
207         INIT_LIST_HEAD(&hd->connections);
208         ida_init(&hd->cport_id_map);
209         hd->buffer_size_max = buffer_size_max;
210
211         return hd;
212 }
213 EXPORT_SYMBOL_GPL(greybus_create_hd);
214
215 int greybus_endo_setup(struct greybus_host_device *hd, u16 endo_id,
216                         u8 ap_intf_id)
217 {
218         struct gb_endo *endo;
219
220         endo = gb_endo_create(hd, endo_id, ap_intf_id);
221         if (IS_ERR(endo))
222                 return PTR_ERR(endo);
223         hd->endo = endo;
224
225         return 0;
226 }
227 EXPORT_SYMBOL_GPL(greybus_endo_setup);
228
229 void greybus_remove_hd(struct greybus_host_device *hd)
230 {
231         /*
232          * Tear down all interfaces, modules, and the endo that is associated
233          * with this host controller before freeing the memory associated with
234          * the host controller.
235          */
236         gb_interfaces_remove(hd);
237         gb_endo_remove(hd->endo);
238         kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
239 }
240 EXPORT_SYMBOL_GPL(greybus_remove_hd);
241
242 static int __init gb_init(void)
243 {
244         int retval;
245
246         if (greybus_disabled())
247                 return -ENODEV;
248
249         BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
250
251         gb_debugfs_init();
252
253         retval = bus_register(&greybus_bus_type);
254         if (retval) {
255                 pr_err("bus_register failed (%d)\n", retval);
256                 goto error_bus;
257         }
258
259         retval = gb_ap_init();
260         if (retval) {
261                 pr_err("gb_ap_init failed (%d)\n", retval);
262                 goto error_ap;
263         }
264
265         retval = gb_operation_init();
266         if (retval) {
267                 pr_err("gb_operation_init failed (%d)\n", retval);
268                 goto error_operation;
269         }
270
271         retval = gb_endo_init();
272         if (retval) {
273                 pr_err("gb_endo_init failed (%d)\n", retval);
274                 goto error_endo;
275         }
276
277         return 0;       /* Success */
278
279 error_endo:
280         gb_operation_exit();
281 error_operation:
282         gb_ap_exit();
283 error_ap:
284         bus_unregister(&greybus_bus_type);
285 error_bus:
286         gb_debugfs_cleanup();
287
288         return retval;
289 }
290 module_init(gb_init);
291
292 static void __exit gb_exit(void)
293 {
294         gb_endo_exit();
295         gb_operation_exit();
296         gb_ap_exit();
297         bus_unregister(&greybus_bus_type);
298         gb_debugfs_cleanup();
299 }
300 module_exit(gb_exit);
301 MODULE_LICENSE("GPL v2");
302 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");