]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/greybus/core.c
greybus: fix error message on parse of cport descriptor size
[karo-tx-linux.git] / drivers / staging / greybus / core.c
1 /*
2  * Greybus "Core"
3  *
4  * Copyright 2014 Google Inc.
5  *
6  * Released under the GPLv2 only.
7  */
8
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11 #include <linux/types.h>
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/device.h>
17
18 #include "greybus.h"
19
20 /* Allow greybus to be disabled at boot if needed */
21 static bool nogreybus;
22 #ifdef MODULE
23 module_param(nogreybus, bool, 0444);
24 #else
25 core_param(nogreybus, bool, 0444);
26 #endif
27 int greybus_disabled(void)
28 {
29         return nogreybus;
30 }
31 EXPORT_SYMBOL_GPL(greybus_disabled);
32
33 static int greybus_match_one_id(struct greybus_module *gmod,
34                                 const struct greybus_module_id *id)
35 {
36         struct greybus_descriptor_module *module;
37
38         module = &gmod->module;
39
40         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
41             (id->vendor != le16_to_cpu(module->vendor)))
42                 return 0;
43
44         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
45             (id->product != le16_to_cpu(module->product)))
46                 return 0;
47
48         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
49             (id->serial_number != le64_to_cpu(module->serial_number)))
50                 return 0;
51
52         return 1;
53 }
54
55 static const struct greybus_module_id *greybus_match_id(
56                 struct greybus_module *gmod,
57                 const struct greybus_module_id *id)
58 {
59         if (id == NULL)
60                 return NULL;
61
62         for (; id->vendor || id->product || id->serial_number ||
63                id->driver_info ; id++) {
64                 if (greybus_match_one_id(gmod, id))
65                         return id;
66         }
67
68         return NULL;
69 }
70
71 static int greybus_module_match(struct device *dev, struct device_driver *drv)
72 {
73         struct greybus_driver *driver = to_greybus_driver(dev->driver);
74         struct greybus_module *gmod = to_greybus_module(dev);
75         const struct greybus_module_id *id;
76
77         id = greybus_match_id(gmod, driver->id_table);
78         if (id)
79                 return 1;
80         /* FIXME - Dyanmic ids? */
81         return 0;
82 }
83
84 static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
85 {
86         /* struct greybus_module *gmod = to_greybus_module(dev); */
87
88         /* FIXME - add some uevents here... */
89         return 0;
90 }
91
92 static 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 greybus_module *gmod = to_greybus_module(dev);
102         const struct greybus_module_id *id;
103         int retval;
104
105         /* match id */
106         id = greybus_match_id(gmod, driver->id_table);
107         if (!id)
108                 return -ENODEV;
109
110         retval = driver->probe(gmod, 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 greybus_module *gmod = to_greybus_module(dev);
121
122         driver->disconnect(gmod);
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(struct greybus_driver *driver)
150 {
151         driver_unregister(&driver->driver);
152 }
153 EXPORT_SYMBOL_GPL(greybus_deregister);
154
155
156 static void greybus_module_release(struct device *dev)
157 {
158         struct greybus_module *gmod = to_greybus_module(dev);
159         int i;
160
161         for (i = 0; i < gmod->num_strings; ++i)
162                 kfree(gmod->string[i]);
163         kfree(gmod);
164 }
165
166
167 const u8 *greybus_string(struct greybus_module *gmod, int id)
168 {
169         int i;
170         struct gmod_string *string;
171
172         if (!gmod)
173                 return NULL;
174
175         for (i = 0; i < gmod->num_strings; ++i) {
176                 string = gmod->string[i];
177                 if (string->id == id)
178                         return &string->string[0];
179         }
180         return NULL;
181 }
182
183 static struct device_type greybus_module_type = {
184         .name =         "greybus_module",
185         .release =      greybus_module_release,
186 };
187
188 static int gb_init_subdevs(struct greybus_module *gmod,
189                            const struct greybus_module_id *id)
190 {
191         int retval;
192
193         /* Allocate all of the different "sub device types" for this device */
194         retval = gb_i2c_probe(gmod, id);
195         if (retval)
196                 goto error_i2c;
197
198         retval = gb_gpio_probe(gmod, id);
199         if (retval)
200                 goto error_gpio;
201
202         retval = gb_sdio_probe(gmod, id);
203         if (retval)
204                 goto error_sdio;
205
206         retval = gb_tty_probe(gmod, id);
207         if (retval)
208                 goto error_tty;
209
210         retval = gb_battery_probe(gmod, id);
211         if (retval)
212                 goto error_battery;
213         return 0;
214
215 error_battery:
216         gb_tty_disconnect(gmod);
217
218 error_tty:
219         gb_sdio_disconnect(gmod);
220
221 error_sdio:
222         gb_gpio_disconnect(gmod);
223
224 error_gpio:
225         gb_i2c_disconnect(gmod);
226
227 error_i2c:
228         return retval;
229 }
230
231 static const struct greybus_module_id fake_gb_id = {
232         GREYBUS_DEVICE(0x42, 0x42)
233 };
234
235 static int create_function(struct greybus_module *gmod,
236                            struct greybus_descriptor_function *function,
237                            size_t desc_size)
238 {
239         if (desc_size != sizeof(*function)) {
240                 dev_err(gmod->dev.parent, "invalid function header size %zu\n",
241                         desc_size);
242                 return -EINVAL;
243         }
244         memcpy(&gmod->function, function, desc_size);
245         return 0;
246 }
247
248 static int create_module(struct greybus_module *gmod,
249                             struct greybus_descriptor_module *module,
250                             size_t desc_size)
251 {
252         if (desc_size != sizeof(*module)) {
253                 dev_err(gmod->dev.parent, "invalid module header size %zu\n",
254                         desc_size);
255                 return -EINVAL;
256         }
257         memcpy(&gmod->module, module, desc_size);
258         return 0;
259 }
260
261 static int create_string(struct greybus_module *gmod,
262                          struct greybus_descriptor_string *string,
263                          size_t desc_size)
264 {
265         int string_size;
266         struct gmod_string *gmod_string;
267
268         if (gmod->num_strings == MAX_STRINGS_PER_MODULE) {
269                 dev_err(gmod->dev.parent,
270                         "too many strings for this module!\n");
271                 return -EINVAL;
272         }
273
274         if (desc_size < sizeof(*string)) {
275                 dev_err(gmod->dev.parent, "invalid string header size %zu\n",
276                         desc_size);
277                 return -EINVAL;
278         }
279
280         string_size = string->length;
281         gmod_string = kzalloc(sizeof(*gmod_string) + string_size + 1, GFP_KERNEL);
282         if (!gmod_string)
283                 return -ENOMEM;
284
285         gmod_string->length = string_size;
286         gmod_string->id = string->id;
287         memcpy(&gmod_string->string, &string->string, string_size);
288
289         gmod->string[gmod->num_strings] = gmod_string;
290         gmod->num_strings++;
291
292         return 0;
293 }
294
295 static int create_cport(struct greybus_module *gmod,
296                         struct greybus_descriptor_cport *cport,
297                         size_t desc_size)
298 {
299         if (gmod->num_cports == MAX_CPORTS_PER_MODULE) {
300                 dev_err(gmod->dev.parent, "too many cports for this module!\n");
301                 return -EINVAL;
302         }
303
304         if (desc_size != sizeof(*cport)) {
305                 dev_err(gmod->dev.parent,
306                         "invalid cport descriptor size %zu\n", desc_size);
307                 return -EINVAL;
308         }
309
310         gmod->cport_ids[gmod->num_cports] = le16_to_cpu(cport->id);
311         gmod->num_cports++;
312
313         return 0;
314 }
315
316 /**
317  * gb_add_module
318  *
319  * Pass in a buffer that _should_ contain a Greybus module manifest
320  * and register a greybus device structure with the kernel core.
321  */
322 void gb_add_module(struct greybus_host_device *hd, u8 module_id,
323                    u8 *data, int size)
324 {
325         struct greybus_module *gmod;
326         struct greybus_manifest *manifest;
327         int retval;
328         int overall_size;
329
330         /* we have to have at _least_ the manifest header */
331         if (size <= sizeof(manifest->header))
332                 return;
333
334         gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
335         if (!gmod)
336                 return;
337
338         gmod->module_number = module_id;
339         gmod->dev.parent = hd->parent;
340         gmod->dev.driver = NULL;
341         gmod->dev.bus = &greybus_bus_type;
342         gmod->dev.type = &greybus_module_type;
343         gmod->dev.groups = greybus_module_groups;
344         gmod->dev.dma_mask = hd->parent->dma_mask;
345         device_initialize(&gmod->dev);
346         dev_set_name(&gmod->dev, "%d", module_id);
347
348         manifest = (struct greybus_manifest *)data;
349         overall_size = le16_to_cpu(manifest->header.size);
350         if (overall_size != size) {
351                 dev_err(hd->parent, "size != manifest header size, %d != %d\n",
352                         size, overall_size);
353                 goto error;
354         }
355
356         /* Validate major/minor number */
357         if (manifest->header.version_major > GREYBUS_VERSION_MAJOR) {
358                 dev_err(hd->parent,
359                         "Manifest version too new (%hhu.%hhu > %hhu.%hhu)\n",
360                         manifest->header.version_major,
361                         manifest->header.version_minor,
362                         GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR);
363                 goto error;
364         }
365
366         size -= sizeof(manifest->header);
367         data += sizeof(manifest->header);
368         while (size > 0) {
369                 struct greybus_descriptor *desc;
370                 u16 desc_size;
371                 size_t data_size;
372
373                 if (size < sizeof(desc->header)) {
374                         dev_err(hd->parent, "remaining size %d too small\n",
375                                 size);
376                         goto error;
377                 }
378                 desc = (struct greybus_descriptor *)data;
379                 desc_size = le16_to_cpu(desc->header.size);
380                 if (size < desc_size) {
381                         dev_err(hd->parent, "descriptor size %d too big\n",
382                                 desc_size);
383                         goto error;
384                 }
385                 data_size = (size_t)desc_size - sizeof(desc->header);
386
387                 switch (le16_to_cpu(desc->header.type)) {
388                 case GREYBUS_TYPE_FUNCTION:
389                         retval = create_function(gmod, &desc->function,
390                                                  data_size);
391                         break;
392
393                 case GREYBUS_TYPE_MODULE:
394                         retval = create_module(gmod, &desc->module,
395                                                   data_size);
396                         break;
397
398                 case GREYBUS_TYPE_STRING:
399                         retval = create_string(gmod, &desc->string, data_size);
400                         break;
401
402                 case GREYBUS_TYPE_CPORT:
403                         retval = create_cport(gmod, &desc->cport, data_size);
404                         break;
405
406                 case GREYBUS_TYPE_INVALID:
407                 default:
408                         dev_err(hd->parent, "invalid descriptor type %d\n",
409                                 desc->header.type);
410                         goto error;
411                 }
412                 if (retval)
413                         goto error;
414                 size -= desc_size;
415                 data += desc_size;
416         }
417
418         retval = gb_init_subdevs(gmod, &fake_gb_id);
419         if (retval)
420                 goto error;
421
422         // FIXME device_add(&gmod->dev);
423
424         //return gmod;
425         return;
426 error:
427         put_device(&gmod->dev);
428         greybus_module_release(&gmod->dev);
429 }
430
431 void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
432 {
433         // FIXME should be the remove_device call...
434 }
435
436 void greybus_remove_device(struct greybus_module *gmod)
437 {
438         /* tear down all of the "sub device types" for this device */
439         gb_i2c_disconnect(gmod);
440         gb_gpio_disconnect(gmod);
441         gb_sdio_disconnect(gmod);
442         gb_tty_disconnect(gmod);
443         gb_battery_disconnect(gmod);
444
445         // FIXME - device_remove(&gmod->dev);
446 }
447
448 static DEFINE_MUTEX(hd_mutex);
449
450 static void free_hd(struct kref *kref)
451 {
452         struct greybus_host_device *hd;
453
454         hd = container_of(kref, struct greybus_host_device, kref);
455
456         kfree(hd);
457 }
458
459 struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
460                                               struct device *parent)
461 {
462         struct greybus_host_device *hd;
463
464         hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
465         if (!hd)
466                 return NULL;
467
468         kref_init(&hd->kref);
469         hd->parent = parent;
470         hd->driver = driver;
471
472         return hd;
473 }
474 EXPORT_SYMBOL_GPL(greybus_create_hd);
475
476 void greybus_remove_hd(struct greybus_host_device *hd)
477 {
478         kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
479 }
480 EXPORT_SYMBOL_GPL(greybus_remove_hd);
481
482
483 static int __init gb_init(void)
484 {
485         int retval;
486
487         retval = gb_debugfs_init();
488         if (retval) {
489                 pr_err("debugfs failed\n");
490                 return retval;
491         }
492
493         retval = bus_register(&greybus_bus_type);
494         if (retval) {
495                 pr_err("bus_register failed\n");
496                 goto error_bus;
497         }
498
499         retval = gb_ap_init();
500         if (retval) {
501                 pr_err("gb_ap_init failed\n");
502                 goto error_ap;
503         }
504
505         retval = gb_gbuf_init();
506         if (retval) {
507                 pr_err("gb_gbuf_init failed\n");
508                 goto error_gbuf;
509         }
510
511         retval = gb_tty_init();
512         if (retval) {
513                 pr_err("gb_tty_init failed\n");
514                 goto error_tty;
515         }
516
517         return 0;
518
519 error_tty:
520         gb_gbuf_exit();
521
522 error_gbuf:
523         gb_ap_exit();
524
525 error_ap:
526         bus_unregister(&greybus_bus_type);
527
528 error_bus:
529         gb_debugfs_cleanup();
530
531         return retval;
532 }
533
534 static void __exit gb_exit(void)
535 {
536         gb_tty_exit();
537         gb_gbuf_exit();
538         gb_ap_exit();
539         bus_unregister(&greybus_bus_type);
540         gb_debugfs_cleanup();
541 }
542
543 module_init(gb_init);
544 module_exit(gb_exit);
545
546 MODULE_LICENSE("GPL");
547 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");