]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/greybus/core.c
greybus: ap: start validating the message better
[mirror_ubuntu-artful-kernel.git] / drivers / staging / greybus / core.c
CommitLineData
c8a797a9
GKH
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>
a239f67c 15#include <linux/slab.h>
c8a797a9
GKH
16#include <linux/device.h>
17
18#include "greybus.h"
19
20/* Allow greybus to be disabled at boot if needed */
21static bool nogreybus;
22#ifdef MODULE
23module_param(nogreybus, bool, 0444);
24#else
25core_param(nogreybus, bool, 0444);
26#endif
27int greybus_disabled(void)
28{
29 return nogreybus;
30}
31EXPORT_SYMBOL_GPL(greybus_disabled);
32
33static int greybus_match_one_id(struct greybus_device *gdev,
6584c8af 34 const struct greybus_module_id *id)
c8a797a9 35{
6dca7b97
GKH
36 struct greybus_descriptor_module_id *module_id;
37 struct greybus_descriptor_serial_number *serial_num;
38
39 module_id = &gdev->module_id;
40 serial_num = &gdev->serial_number;
c8a797a9
GKH
41
42 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
6dca7b97 43 (id->vendor != le16_to_cpu(module_id->vendor)))
c8a797a9
GKH
44 return 0;
45
46 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
6dca7b97 47 (id->product != le16_to_cpu(module_id->product)))
c8a797a9
GKH
48 return 0;
49
50 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
6dca7b97 51 (id->serial_number != le64_to_cpu(serial_num->serial_number)))
c8a797a9
GKH
52 return 0;
53
54 return 1;
55}
56
6584c8af 57static const struct greybus_module_id *greybus_match_id(
c8a797a9 58 struct greybus_device *gdev,
6584c8af 59 const struct greybus_module_id *id)
c8a797a9
GKH
60{
61 if (id == NULL)
62 return NULL;
63
6dca7b97 64 for (; id->vendor || id->product || id->serial_number ||
c8a797a9
GKH
65 id->driver_info ; id++) {
66 if (greybus_match_one_id(gdev, id))
67 return id;
68 }
69
70 return NULL;
71}
72
73static int greybus_device_match(struct device *dev, struct device_driver *drv)
74{
75 struct greybus_driver *driver = to_greybus_driver(dev->driver);
76 struct greybus_device *gdev = to_greybus_device(dev);
6584c8af 77 const struct greybus_module_id *id;
c8a797a9
GKH
78
79 id = greybus_match_id(gdev, driver->id_table);
80 if (id)
81 return 1;
82 /* FIXME - Dyanmic ids? */
83 return 0;
84}
85
86static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
87{
88 /* struct greybus_device *gdev = to_greybus_device(dev); */
89
90 /* FIXME - add some uevents here... */
91 return 0;
92}
93
27fb8310 94static struct bus_type greybus_bus_type = {
c8a797a9
GKH
95 .name = "greybus",
96 .match = greybus_device_match,
97 .uevent = greybus_uevent,
98};
99
100static int greybus_probe(struct device *dev)
101{
102 struct greybus_driver *driver = to_greybus_driver(dev->driver);
103 struct greybus_device *gdev = to_greybus_device(dev);
6584c8af 104 const struct greybus_module_id *id;
c8a797a9
GKH
105 int retval;
106
107 /* match id */
108 id = greybus_match_id(gdev, driver->id_table);
109 if (!id)
110 return -ENODEV;
111
112 retval = driver->probe(gdev, id);
113 if (retval)
114 return retval;
115
116 return 0;
117}
118
119static int greybus_remove(struct device *dev)
120{
121 struct greybus_driver *driver = to_greybus_driver(dev->driver);
122 struct greybus_device *gdev = to_greybus_device(dev);
123
124 driver->disconnect(gdev);
125 return 0;
126}
127
128int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
129 const char *mod_name)
130{
131 int retval;
132
133 if (greybus_disabled())
134 return -ENODEV;
135
136 driver->driver.name = driver->name;
137 driver->driver.probe = greybus_probe;
138 driver->driver.remove = greybus_remove;
139 driver->driver.owner = owner;
140 driver->driver.mod_name = mod_name;
141
142 retval = driver_register(&driver->driver);
143 if (retval)
144 return retval;
145
146 pr_info("registered new driver %s\n", driver->name);
147 return 0;
148}
149EXPORT_SYMBOL_GPL(greybus_register_driver);
150
151void greybus_deregister(struct greybus_driver *driver)
152{
153 driver_unregister(&driver->driver);
154}
155EXPORT_SYMBOL_GPL(greybus_deregister);
156
199d68d4 157
b94295e0
GKH
158static void greybus_module_release(struct device *dev)
159{
160 struct greybus_device *gdev = to_greybus_device(dev);
161 int i;
162
163 for (i = 0; i < gdev->num_strings; ++i)
164 kfree(gdev->string[i]);
165 for (i = 0; i < gdev->num_cports; ++i)
166 kfree(gdev->cport[i]);
167 kfree(gdev);
168}
169
170
e24e7257
GKH
171const u8 *greybus_string(struct greybus_device *gdev, int id)
172{
173 int i;
174 struct gdev_string *string;
175
176 if (!gdev)
177 return NULL;
178
179 for (i = 0; i < gdev->num_strings; ++i) {
180 string = gdev->string[i];
181 if (string->id == id)
182 return &string->string[0];
183 }
184 return NULL;
185}
186
b94295e0
GKH
187static struct device_type greybus_module_type = {
188 .name = "greybus_module",
189 .release = greybus_module_release,
190};
191
a239f67c
GKH
192static int gb_init_subdevs(struct greybus_device *gdev,
193 const struct greybus_module_id *id)
199d68d4
GKH
194{
195 int retval;
196
197 /* Allocate all of the different "sub device types" for this device */
198 retval = gb_i2c_probe(gdev, id);
db6e1fd2
GKH
199 if (retval)
200 goto error_i2c;
201
202 retval = gb_gpio_probe(gdev, id);
203 if (retval)
204 goto error_gpio;
205
206 retval = gb_sdio_probe(gdev, id);
207 if (retval)
208 goto error_sdio;
209
210 retval = gb_tty_probe(gdev, id);
211 if (retval)
212 goto error_tty;
33ea3a3f
GKH
213
214 retval = gb_battery_probe(gdev, id);
215 if (retval)
216 goto error_battery;
199d68d4 217 return 0;
db6e1fd2 218
33ea3a3f
GKH
219error_battery:
220 gb_tty_disconnect(gdev);
221
db6e1fd2
GKH
222error_tty:
223 gb_sdio_disconnect(gdev);
224
225error_sdio:
226 gb_gpio_disconnect(gdev);
227
228error_gpio:
229 gb_i2c_disconnect(gdev);
230
231error_i2c:
232 return retval;
199d68d4
GKH
233}
234
3be03d42
GKH
235static const struct greybus_module_id fake_gb_id = {
236 GREYBUS_DEVICE(0x42, 0x42)
237};
a239f67c 238
526c5c8d 239static int create_function(struct greybus_device *gdev,
3d545326
GKH
240 struct greybus_descriptor_function *function,
241 size_t desc_size)
526c5c8d 242{
3d545326
GKH
243 if (desc_size != sizeof(*function)) {
244 dev_err(gdev->dev.parent, "invalid function header size %zu\n",
b94295e0 245 desc_size);
526c5c8d
GKH
246 return -EINVAL;
247 }
3d545326 248 memcpy(&gdev->function, function, desc_size);
526c5c8d
GKH
249 return 0;
250}
251
252static int create_module_id(struct greybus_device *gdev,
3d545326
GKH
253 struct greybus_descriptor_module_id *module_id,
254 size_t desc_size)
526c5c8d 255{
3d545326
GKH
256 if (desc_size != sizeof(*module_id)) {
257 dev_err(gdev->dev.parent, "invalid module header size %zu\n",
b94295e0 258 desc_size);
526c5c8d
GKH
259 return -EINVAL;
260 }
3d545326 261 memcpy(&gdev->module_id, module_id, desc_size);
526c5c8d
GKH
262 return 0;
263}
264
265static int create_serial_number(struct greybus_device *gdev,
3d545326
GKH
266 struct greybus_descriptor_serial_number *serial_num,
267 size_t desc_size)
526c5c8d 268{
3d545326
GKH
269 if (desc_size != sizeof(*serial_num)) {
270 dev_err(gdev->dev.parent, "invalid serial number header size %zu\n",
b94295e0 271 desc_size);
526c5c8d
GKH
272 return -EINVAL;
273 }
3d545326 274 memcpy(&gdev->serial_number, serial_num, desc_size);
526c5c8d
GKH
275 return 0;
276}
277
278static int create_string(struct greybus_device *gdev,
3d545326
GKH
279 struct greybus_descriptor_string *string,
280 size_t desc_size)
526c5c8d
GKH
281{
282 int string_size;
3d545326 283 struct gdev_string *gdev_string;
526c5c8d
GKH
284
285 if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
b94295e0
GKH
286 dev_err(gdev->dev.parent,
287 "too many strings for this module!\n");
526c5c8d
GKH
288 return -EINVAL;
289 }
290
3d545326
GKH
291 if (desc_size < sizeof(*string)) {
292 dev_err(gdev->dev.parent, "invalid string header size %zu\n",
b94295e0 293 desc_size);
526c5c8d
GKH
294 return -EINVAL;
295 }
296
3d545326
GKH
297 string_size = le16_to_cpu(string->length);
298 gdev_string = kzalloc(sizeof(*gdev_string) + string_size + 1, GFP_KERNEL);
299 if (!gdev_string)
526c5c8d
GKH
300 return -ENOMEM;
301
3d545326
GKH
302 gdev_string->length = string_size;
303 gdev_string->id = string->id;
304 memcpy(&gdev_string->string, &string->string, string_size);
b94295e0 305
3d545326 306 gdev->string[gdev->num_strings] = gdev_string;
526c5c8d
GKH
307 gdev->num_strings++;
308
309 return 0;
310}
311
b94295e0 312static int create_cport(struct greybus_device *gdev,
3d545326
GKH
313 struct greybus_descriptor_cport *cport,
314 size_t desc_size)
b94295e0 315{
3d545326 316 struct gdev_cport *gdev_cport;
b94295e0
GKH
317
318 if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
319 dev_err(gdev->dev.parent, "too many cports for this module!\n");
320 return -EINVAL;
321 }
322
3d545326 323 if (desc_size != sizeof(*cport)) {
b94295e0 324 dev_err(gdev->dev.parent,
3d545326 325 "invalid serial number header size %zu\n", desc_size);
b94295e0
GKH
326 return -EINVAL;
327 }
328
3d545326
GKH
329 gdev_cport = kzalloc(sizeof(*gdev_cport), GFP_KERNEL);
330 if (!gdev_cport)
b94295e0
GKH
331 return -ENOMEM;
332
3d545326
GKH
333 gdev_cport->number = le16_to_cpu(cport->number);
334 gdev_cport->size = le16_to_cpu(cport->size);
335 gdev_cport->speed = cport->speed;
b94295e0 336
3d545326 337 gdev->cport[gdev->num_cports] = gdev_cport;
b94295e0
GKH
338 gdev->num_cports++;
339
340 return 0;
341}
342
a239f67c 343/**
05ad189c 344 * greybus_new_module:
a239f67c 345 *
05ad189c
AE
346 * Pass in a buffer that _should_ contain a Greybus module manifest
347 * and spit out a greybus device structure.
a239f67c 348 */
6779997d
GKH
349void gb_add_module(struct greybus_host_device *hd, u8 module_id, u8 *data)
350{
351 // FIXME - should be the new module call...
352}
353
05ad189c 354struct greybus_device *greybus_new_module(struct device *parent,
b94295e0 355 int module_number, u8 *data, int size)
a239f67c
GKH
356{
357 struct greybus_device *gdev;
badad68e 358 struct greybus_manifest *manifest;
a239f67c
GKH
359 int retval;
360 int overall_size;
a239f67c
GKH
361 u8 version_major;
362 u8 version_minor;
363
05ad189c 364 /* we have to have at _least_ the manifest header */
badad68e 365 if (size <= sizeof(manifest->header))
a239f67c
GKH
366 return NULL;
367
368 gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
369 if (!gdev)
370 return NULL;
371
372 gdev->module_number = module_number;
b94295e0
GKH
373 gdev->dev.parent = parent;
374 gdev->dev.driver = NULL;
375 gdev->dev.bus = &greybus_bus_type;
376 gdev->dev.type = &greybus_module_type;
377 gdev->dev.groups = greybus_module_groups;
378 gdev->dev.dma_mask = parent->dma_mask;
379 device_initialize(&gdev->dev);
380 dev_set_name(&gdev->dev, "%d", module_number);
a239f67c 381
badad68e
AE
382 manifest = (struct greybus_manifest *)data;
383 overall_size = le16_to_cpu(manifest->header.size);
a239f67c 384 if (overall_size != size) {
05ad189c
AE
385 dev_err(parent, "size != manifest header size, %d != %d\n",
386 size, overall_size);
a239f67c
GKH
387 goto error;
388 }
389
badad68e
AE
390 version_major = manifest->header.version_major;
391 version_minor = manifest->header.version_minor;
a239f67c 392
a1dc62b0
GKH
393 /* Validate major/minor number */
394 if ((version_major != GREYBUS_VERSION_MAJOR) ||
395 (version_minor != GREYBUS_VERSION_MINOR)) {
396 dev_err(parent,
397 "Invalid greybus versions, expected %d.%d, got %d.%d\n",
398 GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR,
399 version_major, version_minor);
400 goto error;
401 }
a239f67c 402
badad68e
AE
403 size -= sizeof(manifest->header);
404 data += sizeof(manifest->header);
a239f67c 405 while (size > 0) {
e82bef42
AE
406 struct greybus_descriptor *desc;
407 u16 desc_size;
408 size_t data_size;
409
57fc0a11
AE
410 if (size < sizeof(desc->header)) {
411 dev_err(parent, "remaining size %d too small\n", size);
412 goto error;
413 }
a239f67c
GKH
414 desc = (struct greybus_descriptor *)data;
415 desc_size = le16_to_cpu(desc->header.size);
57fc0a11
AE
416 if (size < desc_size) {
417 dev_err(parent, "descriptor size %d too big\n",
418 desc_size);
419 goto error;
420 }
e82bef42 421 data_size = (size_t)desc_size - sizeof(desc->header);
a239f67c 422
a22e15a1 423 switch (le16_to_cpu(desc->header.type)) {
a239f67c 424 case GREYBUS_TYPE_FUNCTION:
3d545326
GKH
425 retval = create_function(gdev, &desc->function,
426 data_size);
a239f67c
GKH
427 break;
428
429 case GREYBUS_TYPE_MODULE_ID:
3d545326
GKH
430 retval = create_module_id(gdev, &desc->module_id,
431 data_size);
a239f67c
GKH
432 break;
433
434 case GREYBUS_TYPE_SERIAL_NUMBER:
3d545326
GKH
435 retval = create_serial_number(gdev,
436 &desc->serial_number,
437 data_size);
526c5c8d
GKH
438 break;
439
440 case GREYBUS_TYPE_STRING:
3d545326 441 retval = create_string(gdev, &desc->string, data_size);
526c5c8d
GKH
442 break;
443
b94295e0 444 case GREYBUS_TYPE_CPORT:
3d545326 445 retval = create_cport(gdev, &desc->cport, data_size);
a239f67c 446 break;
b94295e0 447
a239f67c
GKH
448 case GREYBUS_TYPE_INVALID:
449 default:
b94295e0
GKH
450 dev_err(parent, "invalid descriptor type %d\n",
451 desc->header.type);
a239f67c
GKH
452 goto error;
453 }
526c5c8d
GKH
454 if (retval)
455 goto error;
456 size -= desc_size;
457 data += desc_size;
a239f67c 458 }
526c5c8d 459
a239f67c
GKH
460 retval = gb_init_subdevs(gdev, &fake_gb_id);
461 if (retval)
462 goto error;
b94295e0
GKH
463
464 // FIXME device_add(&gdev->dev);
465
466
a239f67c
GKH
467 return gdev;
468error:
a5808add 469 put_device(&gdev->dev);
b94295e0 470 greybus_module_release(&gdev->dev);
a239f67c
GKH
471 return NULL;
472}
473
6779997d
GKH
474void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
475{
476 // FIXME should be the remove_device call...
477}
478
b94295e0 479void greybus_remove_device(struct greybus_device *gdev)
db6e1fd2
GKH
480{
481 /* tear down all of the "sub device types" for this device */
482 gb_i2c_disconnect(gdev);
483 gb_gpio_disconnect(gdev);
484 gb_sdio_disconnect(gdev);
485 gb_tty_disconnect(gdev);
33ea3a3f 486 gb_battery_disconnect(gdev);
b94295e0
GKH
487
488 // FIXME - device_remove(&gdev->dev);
db6e1fd2 489}
199d68d4 490
68f1fc4d
GKH
491static DEFINE_MUTEX(hd_mutex);
492
493static void free_hd(struct kref *kref)
494{
495 struct greybus_host_device *hd;
496
497 hd = container_of(kref, struct greybus_host_device, kref);
498
499 kfree(hd);
500}
501
a39879fc
GKH
502struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
503 struct device *parent)
504{
505 struct greybus_host_device *hd;
506
507 hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
508 if (!hd)
509 return NULL;
510
511 kref_init(&hd->kref);
772149b6
GKH
512 hd->parent = parent;
513 hd->driver = driver;
a39879fc
GKH
514
515 return hd;
516}
517EXPORT_SYMBOL_GPL(greybus_create_hd);
518
68f1fc4d
GKH
519void greybus_remove_hd(struct greybus_host_device *hd)
520{
521 kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
522}
523EXPORT_SYMBOL_GPL(greybus_remove_hd);
524
a39879fc 525
503c1cdb 526static int __init gb_init(void)
199d68d4 527{
db6e1fd2
GKH
528 int retval;
529
de536e30 530 retval = gb_debugfs_init();
168db1cd
GKH
531 if (retval) {
532 pr_err("debugfs failed\n");
db6e1fd2 533 return retval;
168db1cd 534 }
db6e1fd2 535
27fb8310 536 retval = bus_register(&greybus_bus_type);
168db1cd
GKH
537 if (retval) {
538 pr_err("bus_register failed\n");
27fb8310 539 goto error_bus;
168db1cd 540 }
27fb8310 541
45f3678b 542 retval = gb_ap_init();
168db1cd 543 if (retval) {
45f3678b
GKH
544 pr_err("gb_ap_init failed\n");
545 goto error_ap;
168db1cd 546 }
de536e30 547
45f3678b
GKH
548 retval = gb_gbuf_init();
549 if (retval) {
550 pr_err("gb_gbuf_init failed\n");
551 goto error_gbuf;
552 }
27fb8310
GKH
553
554 retval = gb_tty_init();
168db1cd
GKH
555 if (retval) {
556 pr_err("gb_tty_init failed\n");
27fb8310 557 goto error_tty;
168db1cd 558 }
27fb8310 559
199d68d4 560 return 0;
27fb8310
GKH
561
562error_tty:
45f3678b
GKH
563 gb_gbuf_exit();
564
565error_gbuf:
566 gb_ap_exit();
de536e30 567
45f3678b 568error_ap:
27fb8310
GKH
569 bus_unregister(&greybus_bus_type);
570
571error_bus:
de536e30 572 gb_debugfs_cleanup();
27fb8310
GKH
573
574 return retval;
199d68d4
GKH
575}
576
503c1cdb 577static void __exit gb_exit(void)
199d68d4 578{
db6e1fd2 579 gb_tty_exit();
45f3678b
GKH
580 gb_gbuf_exit();
581 gb_ap_exit();
27fb8310 582 bus_unregister(&greybus_bus_type);
de536e30 583 gb_debugfs_cleanup();
199d68d4
GKH
584}
585
586module_init(gb_init);
587module_exit(gb_exit);
588
c8a797a9
GKH
589MODULE_LICENSE("GPL");
590MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");